On 2017-04-17 21:49, Jef Driesen wrote:
On 14-04-17 22:04, Anton Lundin wrote:
On 14 April, 2017 - Jef Driesen wrote:
On 2017-04-13 17:04, Jef Driesen wrote:
I tried a different approach yesterday. Instead of adding 1024 to
the calibration value, I simply used the stored value as is, and
calculated the average ppO2 over all three sensors. Then I plotted
all those values against the average ppO2 reported by the device.
And guess what, there is a nice linear relationship between the two!
Doing a linear regression on the data gives a scaling factor of 2.2.
Interesting find.
For the example above this gives:
Sensor 0: 0.642 = 33 mV * 885 / 100000.0 * 2.2
Sensor 1: 0.630 = 29 mV * 989 / 100000.0 * 2.2
Sensor 2: 0.674 = 26 mv * 1179 / 100000.0 * 2.2
As you can see, the average ppO2 (0.648) is now very close to the
average ppO2 reported by the device (0.65). This seems to be true
for all samples. The largest difference is now 0.018.
The next question is of course what's the source of this factor 2.2?
Could it be that the calibration value is stored in some odd format,
and
thats where the / 100000.0 * 2.2 part comes from?
My first thought was that it represents some kind of relative value.
If you look at one of my previous emails, you'll notice that the
default value for the calibration (when not yet calibrated) is 2100
for the Petrel. And the calibration values for the Predator are all
near the value 1000. Relative that's a factor of 2.1. That's not close
enough to 2.2 to produce correct ppO2 values, but it's the only
explanation I have that makes some sense to me.
BTW, the fact that the calibration values are near 1000 is also why
adding 1024 worked for most samples. If the value is a bit higher than
1000, then the result is pretty close to multiplying with 2.2.
And is correct for all Predators?
How did it line up on the petrels?
I only checked for the predators. For the petrel, the results are
already correct without the 2.2 scaling factor. So applying it there
too, will produce wrong results. So this is most likely something
specific to the predators only.
I've implemented the scaling factor now. See attached set of patches. It
took me a bit longer than expected because there were a few cases where
the ppO2 still ended up being zero. And that turned out to be for dives
without external O2 sensors enabled (e.g. fixed setpoint mode). But the
tricky part was that the external PPO2 bit seems to be reversed.
According to the documentation [1] external PPO2 is 1 and internal PPO2
is 0. But based on the data I have, it seems to be the opposite.
BTW, I wonder if we should ignore the setpoint value when external O2
sensors are used? Are setpoint still used in such case?
[1]
http://lists.subsurface-divelog.org/pipermail/subsurface/2017-April/028144.html
Jef
From 4e97d96246a5500865585d93c96be17939705d98 Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <d...@hohndel.org>
Date: Fri, 6 Feb 2015 09:56:21 -0800
Subject: [PATCH 1/4] Predator: don't report PPO2 unless in CC mode
Sending this in OC mode is redundant and might confuse applications that
assume they only get PPO2 data in CC mode.
Signed-off-by: Dirk Hohndel <d...@hohndel.org>
---
src/shearwater_predator_parser.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c
index 039926f..c71c9d7 100644
--- a/src/shearwater_predator_parser.c
+++ b/src/shearwater_predator_parser.c
@@ -422,11 +422,11 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
// Status flags.
unsigned int status = data[offset + 11];
- // PPO2
- sample.ppo2 = data[offset + 6] / 100.0;
- if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
-
if ((status & OC) == 0) {
+ // PPO2
+ sample.ppo2 = data[offset + 6] / 100.0;
+ if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
+
// Setpoint
if (parser->petrel) {
sample.setpoint = data[offset + 18] / 100.0;
--
2.11.0
From fe5e519519a3bae9637dcc2467b3d0354f47c631 Mon Sep 17 00:00:00 2001
From: Anton Lundin <gla...@acc.umu.se>
Date: Wed, 14 Oct 2015 19:49:25 +0200
Subject: [PATCH 2/4] shearwater: Report individual sensor values
This reads the reported mV values from the sensors, and based on the
calibration values converts it into a ppo2 value to report.
Signed-off-by: Anton Lundin <gla...@acc.umu.se>
---
src/shearwater_predator_parser.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c
index c71c9d7..9b80fa5 100644
--- a/src/shearwater_predator_parser.c
+++ b/src/shearwater_predator_parser.c
@@ -61,6 +61,7 @@ struct shearwater_predator_parser_t {
unsigned int ngasmixes;
unsigned int oxygen[NGASMIXES];
unsigned int helium[NGASMIXES];
+ unsigned int calibration[3];
dc_divemode_t mode;
};
@@ -281,6 +282,23 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
offset += parser->samplesize;
}
+ // Cache sensor calibration for later use
+ parser->calibration[0] = array_uint16_be(data + 87);
+ parser->calibration[1] = array_uint16_be(data + 89);
+ parser->calibration[2] = array_uint16_be(data + 91);
+ // The Predator expects the mV output of the cells to be within 30mV to
+ // 70mV in 100% O2 at 1 atmosphere.
+ // Values below 1000 implies that a sensor wouldn't have been able to
+ // calibrate, which is obviously bogus. In one example I found that
+ // such a computer produced the right value if you added 1024
+ // to the calibration value. Bad mem or old bug?
+ if (parser->calibration[0] < 1000)
+ parser->calibration[0] += 0x0400;
+ if (parser->calibration[1] < 1000)
+ parser->calibration[1] += 0x0400;
+ if (parser->calibration[2] < 1000)
+ parser->calibration[2] += 0x0400;
+
// Cache the data for later use.
parser->headersize = headersize;
parser->footersize = footersize;
@@ -424,8 +442,14 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
if ((status & OC) == 0) {
// PPO2
- sample.ppo2 = data[offset + 6] / 100.0;
- if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
+ sample.ppo2 = data[offset + 12] * parser->calibration[0] / 100000.0;
+ if (callback && (data[86] & 0x01)) callback (DC_SAMPLE_PPO2, sample, userdata);
+
+ sample.ppo2 = data[offset + 14] * parser->calibration[1] / 100000.0;
+ if (callback && (data[86] & 0x02)) callback (DC_SAMPLE_PPO2, sample, userdata);
+
+ sample.ppo2 = data[offset + 15] * parser->calibration[2] / 100000.0;
+ if (callback && (data[86] & 0x04)) callback (DC_SAMPLE_PPO2, sample, userdata);
// Setpoint
if (parser->petrel) {
--
2.11.0
From f588b32819c496c108cd83b9b06fa1efeaeaf16f Mon Sep 17 00:00:00 2001
From: Jef Driesen <jefdrie...@users.sourceforge.net>
Date: Thu, 13 Apr 2017 21:26:56 +0200
Subject: [PATCH 3/4] Use an extra scaling factor for the calibration
The Shearwater Predator seems to need an additional scaling factor for
the O2 sensor calibration.
The calibration values for the Petrel are typically in the range 1600 to
2400, while for Predator they are much smaller, with values in the range
800 to 1400. The consequence is that the calculated ppO2 values are too
low for the Predator. The previous fix, which uses a constant offset for
values below 1000, doesn't always produce reasonable ppO2 values.
Especially if the callibration value is just above this threshold.
The scaling factor 2.2 is based on a linear regression between the
average ppO2 reported by the dive computer, and the average ppO2
calculated over all (calibrated) sensors using the raw calibration
value.
---
src/parser.c | 4 ++--
src/shearwater_petrel.h | 2 +-
src/shearwater_predator.h | 2 +-
src/shearwater_predator_parser.c | 35 +++++++++++++++++------------------
4 files changed, 21 insertions(+), 22 deletions(-)
diff --git a/src/parser.c b/src/parser.c
index 98d2c89..9fdb1a9 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -149,10 +149,10 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
rc = atomics_cobalt_parser_create (&parser, context);
break;
case DC_FAMILY_SHEARWATER_PREDATOR:
- rc = shearwater_predator_parser_create (&parser, context);
+ rc = shearwater_predator_parser_create (&parser, context, model);
break;
case DC_FAMILY_SHEARWATER_PETREL:
- rc = shearwater_petrel_parser_create (&parser, context);
+ rc = shearwater_petrel_parser_create (&parser, context, model);
break;
case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_parser_create (&parser, context);
diff --git a/src/shearwater_petrel.h b/src/shearwater_petrel.h
index 8b927d6..c23bb74 100644
--- a/src/shearwater_petrel.h
+++ b/src/shearwater_petrel.h
@@ -34,7 +34,7 @@ dc_status_t
shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, const char *name);
dc_status_t
-shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context);
+shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus
}
diff --git a/src/shearwater_predator.h b/src/shearwater_predator.h
index f21d445..4665f80 100644
--- a/src/shearwater_predator.h
+++ b/src/shearwater_predator.h
@@ -34,7 +34,7 @@ dc_status_t
shearwater_predator_device_open (dc_device_t **device, dc_context_t *context, const char *name);
dc_status_t
-shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context);
+shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus
}
diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c
index 9b80fa5..57a2694 100644
--- a/src/shearwater_predator_parser.c
+++ b/src/shearwater_predator_parser.c
@@ -48,10 +48,14 @@
#define NGASMIXES 10
+#define PREDATOR 2
+#define PETREL 3
+
typedef struct shearwater_predator_parser_t shearwater_predator_parser_t;
struct shearwater_predator_parser_t {
dc_parser_t base;
+ unsigned int model;
unsigned int petrel;
unsigned int samplesize;
// Cached fields.
@@ -61,7 +65,7 @@ struct shearwater_predator_parser_t {
unsigned int ngasmixes;
unsigned int oxygen[NGASMIXES];
unsigned int helium[NGASMIXES];
- unsigned int calibration[3];
+ double calibration[3];
dc_divemode_t mode;
};
@@ -106,7 +110,7 @@ shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned
static dc_status_t
-shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int petrel)
+shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int petrel)
{
shearwater_predator_parser_t *parser = NULL;
const dc_parser_vtable_t *vtable = NULL;
@@ -131,6 +135,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig
}
// Set the default values.
+ parser->model = model;
parser->petrel = petrel;
parser->samplesize = samplesize;
parser->cached = 0;
@@ -150,16 +155,16 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig
dc_status_t
-shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context)
+shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
- return shearwater_common_parser_create (out, context, 0);
+ return shearwater_common_parser_create (out, context, model, 0);
}
dc_status_t
-shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context)
+shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
- return shearwater_common_parser_create (out, context, 1);
+ return shearwater_common_parser_create (out, context, model, 1);
}
@@ -286,18 +291,12 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
parser->calibration[0] = array_uint16_be(data + 87);
parser->calibration[1] = array_uint16_be(data + 89);
parser->calibration[2] = array_uint16_be(data + 91);
- // The Predator expects the mV output of the cells to be within 30mV to
- // 70mV in 100% O2 at 1 atmosphere.
- // Values below 1000 implies that a sensor wouldn't have been able to
- // calibrate, which is obviously bogus. In one example I found that
- // such a computer produced the right value if you added 1024
- // to the calibration value. Bad mem or old bug?
- if (parser->calibration[0] < 1000)
- parser->calibration[0] += 0x0400;
- if (parser->calibration[1] < 1000)
- parser->calibration[1] += 0x0400;
- if (parser->calibration[2] < 1000)
- parser->calibration[2] += 0x0400;
+ if (parser->model == PREDATOR) {
+ // The Predator needs an additional scaling factor.
+ for (size_t i = 0; i < 3; ++i) {
+ parser->calibration[i] *= 2.2;
+ }
+ }
// Cache the data for later use.
parser->headersize = headersize;
--
2.11.0
From ac4bfff06f4b5af0d5c13636bca9e0d6bb37fef0 Mon Sep 17 00:00:00 2001
From: Jef Driesen <jefdrie...@users.sourceforge.net>
Date: Mon, 8 May 2017 19:24:32 +0200
Subject: [PATCH 4/4] Report the ppO2 in external O2 sensor mode only
The O2 sensor millivolt values are only valid if external O2 sensor
monitoring is enabled.
Note that the interpretation of the PPO2 status bit appears to be
reversed (0=external and 1=internal).
---
src/shearwater_predator_parser.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c
index 57a2694..9f27d6d 100644
--- a/src/shearwater_predator_parser.c
+++ b/src/shearwater_predator_parser.c
@@ -441,14 +441,16 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
if ((status & OC) == 0) {
// PPO2
- sample.ppo2 = data[offset + 12] * parser->calibration[0] / 100000.0;
- if (callback && (data[86] & 0x01)) callback (DC_SAMPLE_PPO2, sample, userdata);
+ if ((status & PPO2_EXTERNAL) == 0) {
+ sample.ppo2 = data[offset + 12] * parser->calibration[0] / 100000.0;
+ if (callback && (data[86] & 0x01)) callback (DC_SAMPLE_PPO2, sample, userdata);
- sample.ppo2 = data[offset + 14] * parser->calibration[1] / 100000.0;
- if (callback && (data[86] & 0x02)) callback (DC_SAMPLE_PPO2, sample, userdata);
+ sample.ppo2 = data[offset + 14] * parser->calibration[1] / 100000.0;
+ if (callback && (data[86] & 0x02)) callback (DC_SAMPLE_PPO2, sample, userdata);
- sample.ppo2 = data[offset + 15] * parser->calibration[2] / 100000.0;
- if (callback && (data[86] & 0x04)) callback (DC_SAMPLE_PPO2, sample, userdata);
+ sample.ppo2 = data[offset + 15] * parser->calibration[2] / 100000.0;
+ if (callback && (data[86] & 0x04)) callback (DC_SAMPLE_PPO2, sample, userdata);
+ }
// Setpoint
if (parser->petrel) {
--
2.11.0
_______________________________________________
subsurface mailing list
subsurface@subsurface-divelog.org
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface