From f8b5927284b6ae32651e0007d69affac7e705598 Mon Sep 17 00:00:00 2001 From: "G. Ramos" Date: Tue, 24 Aug 2021 13:04:47 +0100 Subject: [PATCH 1/2] Update of the BITalino sensors transfer functions (according to PLUX datasheets) --- .../bitalino/util/SensorDataConverter.java | 110 +++++++++++------- .../util/SensorDataConverterTest.java | 74 +++++++++--- 2 files changed, 126 insertions(+), 58 deletions(-) diff --git a/src/main/java/com/bitalino/util/SensorDataConverter.java b/src/main/java/com/bitalino/util/SensorDataConverter.java index 2610878..7c244e6 100644 --- a/src/main/java/com/bitalino/util/SensorDataConverter.java +++ b/src/main/java/com/bitalino/util/SensorDataConverter.java @@ -26,6 +26,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.Arrays; /** * This class holds methods for converting/scaling raw data from BITalino @@ -34,20 +35,27 @@ public class SensorDataConverter { private static final double VCC = 3.3; // volts - private static final int ACC_MIN = 185; - private static final int ACC_MAX = 275; + private static final int NBR_BITALINO_CHANNELS = 6; + private static final int EMG_GAIN = 1009; + private static final int ECG_GAIN = 1100; + private static final double EDA_SCALE_FACTOR = 0.132; + private static final int EEG_GAIN = 41782; /** * ElectroMyoGraphy conversion. * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. - * @return a value ranging between -1.65 and 1.65mV + * @return a value ranging between -1.64 and 1.64mV */ - public static double scaleEMG(final int port, final int raw) { - final double result = (raw * VCC / getResolution(port) - VCC / 2); + public static double scaleEMG(final int port, final Integer[] activePorts, final int raw) { + final double result = + ((raw * VCC / getResolution(port, activePorts) - VCC / 2) * 1000) / EMG_GAIN; return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP) .doubleValue(); } @@ -57,12 +65,15 @@ public static double scaleEMG(final int port, final int raw) { * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. * @return a value ranging between -1.5 and 1.5mV */ - public static double scaleECG(final int port, final int raw) { - final double result = (((raw / getResolution(port) -0.5)*VCC) / 1100) * 1000; + public static double scaleECG(final int port, final Integer[] activePorts, final int raw) { + final double result = (((raw / getResolution(port, activePorts) - 0.5) * VCC) / ECG_GAIN) * 1000; return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP) .doubleValue(); } @@ -70,18 +81,20 @@ public static double scaleECG(final int port, final int raw) { /** * Accelerometer conversion based on reference calibration values. If you want * to acquire more precise values, use - * {@link #scaleAccelerometerWithPrecision(int, int, int, int) + * {@link #scaleAccelerometerWithPrecision(int, Integer[], int) * scaleAccelerometerWithPrecision} method. * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. - * @return a value ranging between -5 and 4.5Gs + * @return a value ranging between -3 and 3g */ - public static double scaleAccelerometer(final int port, final int raw) { - final double result = scaleAccelerometerWithPrecision(port, raw, ACC_MIN, - ACC_MAX); + public static double scaleAccelerometer(final int port, final Integer[] activePorts, final int raw) { + final double result = scaleAccelerometerWithPrecision(port, activePorts, raw); return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP) .doubleValue(); } @@ -91,16 +104,17 @@ public static double scaleAccelerometer(final int port, final int raw) { * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. - * @param min - * the calibration minimum value - * @param max - * the calibration maximum value - * @return a value ranging between -3 and 3Gs + * @return a value ranging between -4.85 and 4.85g (6 bits) or between -4.85 and 4.99 (10 bits). */ - public static double scaleAccelerometerWithPrecision(final int port, - final int raw, final int min, final int max) { + public static double scaleAccelerometerWithPrecision(final int port, final Integer[] activePorts, + final int raw) { + int min = getResolution(port, activePorts) == 1023 ? 400 : 25; + int max = getResolution(port, activePorts) == 1023 ? 608 : 38; return 2 * ((double)(raw - min) / (max - min)) - 1; } @@ -109,19 +123,17 @@ public static double scaleAccelerometerWithPrecision(final int port, * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. - * @return a value ranging from 1 and inf uS (micro Siemens), - * beware might return Double.POSITIVE_INFINITY + * @return a value ranging from 0 to 25 uS (micro Siemens). */ - public static double scaleEDA(final int port, final int raw) { - // need to round maximum value that otherwise is 1.05496875 - final double ohm = 1 - ( (double)raw /(double)1023); - double result = 1/ohm; - if (result != Double.POSITIVE_INFINITY) - result = new BigDecimal(result).setScale(4, RoundingMode.HALF_UP) + public static double scaleEDA(final int port, final Integer[] activePorts, final int raw) { + final double result = ((raw / getResolution(port, activePorts)) * VCC) / EDA_SCALE_FACTOR; + return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP) .doubleValue(); - return result; } /** @@ -129,12 +141,15 @@ public static double scaleEDA(final int port, final int raw) { * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. * @return a value ranging from 0 and 100%. */ - public static double scaleLuminosity(final int port, final int raw) { - return 100 * (raw / getResolution(port)); + public static double scaleLuminosity(final int port, final Integer[] activePorts, final int raw) { + return 100 * (raw / getResolution(port, activePorts)); } /** @@ -142,15 +157,18 @@ public static double scaleLuminosity(final int port, final int raw) { * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. * @param celsius * true:use celsius as metric, * false: fahrenheit is used. - * @return a value ranging between -40 and 125 Celsius (-40 and 257 Fahrenheit) + * @return a value ranging between -50 and 280 Celsius (-58 and 536 Fahrenheit) */ - public static double scaleTMP(final int port, final int raw, boolean celsius){ - double result = (((raw/getResolution(port))*VCC) - 0.5)*100; + public static double scaleTMP(final int port, final Integer[] activePorts, final int raw, boolean celsius){ + double result = (((raw/getResolution(port, activePorts))*VCC) - 0.5)*100; if (!celsius) // Convert to fahrenheit @@ -165,12 +183,15 @@ public static double scaleTMP(final int port, final int raw, boolean celsius){ * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. * @return a value ranging between -50% and 50% */ - public static double scalePZT(final int port, final int raw){ - double result = ((raw/getResolution(port)) - 0.5)*100; + public static double scalePZT(final int port, final Integer[] activePorts, final int raw){ + double result = ((raw/getResolution(port, activePorts)) - 0.5)*100; return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP) .doubleValue(); @@ -181,15 +202,16 @@ public static double scalePZT(final int port, final int raw){ * * @param port * the port where the raw value was read from. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. - * @return a value ranging between -41.5 and 41.5 microvolt + * @return a value ranging between -39.49 and 39.49 microvolt */ - public static double scaleEEG(final int port, final int raw){ - double G_ECG = 40000; // sensor gain - + public static double scaleEEG(final int port, final Integer[] activePorts, final int raw){ // result rescaled to microvolt - double result = (((raw/getResolution(port))-0.5)*VCC)/G_ECG; + double result = (((raw/getResolution(port, activePorts))-0.5)*VCC)/EEG_GAIN; result = result*Math.pow(10, 6); return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP) @@ -203,10 +225,14 @@ public static double scaleEEG(final int port, final int raw){ * From port 4 to 5, the resolution is 6-bit, thus 2^6 - 1 = 63. * * @param port + * index of the port under analysis. + * @param activePorts + * array containing the list of active ports, for example, when the 6 + * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @return the resolution (maximum value) for a certain port. */ - private static final double getResolution(final int port) { - return (double) port < 4 ? 1023 : 63; + private static final double getResolution(final int port, final Integer[] activePorts) { + return (double) activePorts.length > NBR_BITALINO_CHANNELS - 2 && Arrays.asList(activePorts).indexOf(port) < NBR_BITALINO_CHANNELS - 2 || activePorts.length <= NBR_BITALINO_CHANNELS - 2 ? 1023 : 63; } } diff --git a/src/test/java/com/bitalino/util/SensorDataConverterTest.java b/src/test/java/com/bitalino/util/SensorDataConverterTest.java index d87947d..1b53770 100644 --- a/src/test/java/com/bitalino/util/SensorDataConverterTest.java +++ b/src/test/java/com/bitalino/util/SensorDataConverterTest.java @@ -32,50 +32,92 @@ public class SensorDataConverterTest { @Test public void test_emg_conversion() { - assertEquals(SensorDataConverter.scaleEMG(0, 0), -1.65); - assertEquals(SensorDataConverter.scaleEMG(0, 1023), 1.65); + assertEquals(SensorDataConverter.scaleEMG(0, new Integer[]{0}, 0), -1.64); + assertEquals(SensorDataConverter.scaleEMG(5, new Integer[]{1, 2, 3, 5}, 0), -1.64); + assertEquals(SensorDataConverter.scaleEMG(5, new Integer[]{0, 1, 2, 3, 5}, 0), -1.64); + assertEquals(SensorDataConverter.scaleEMG(5, new Integer[]{0, 1, 2, 3, 5}, 63),1.64); + assertEquals(SensorDataConverter.scaleEMG(3, new Integer[]{0, 1, 2, 3, 5},1023),1.64); + assertEquals(SensorDataConverter.scaleEMG(0, new Integer[]{0}, 1023),1.64); } @Test public void test_ecg_conversion() { - assertEquals(SensorDataConverter.scaleECG(0, 0), -1.5); - assertEquals(SensorDataConverter.scaleECG(0, 1023), 1.5); + assertEquals(SensorDataConverter.scaleECG(0, new Integer[]{0}, 0), -1.5); + assertEquals(SensorDataConverter.scaleECG(5, new Integer[]{1, 2, 3, 5}, 0), -1.5); + assertEquals(SensorDataConverter.scaleECG(5, new Integer[]{0, 1, 2, 3, 5}, 0), -1.5); + assertEquals(SensorDataConverter.scaleECG(5, new Integer[]{0, 1, 2, 3, 5}, 63),1.5); + assertEquals(SensorDataConverter.scaleECG(3, new Integer[]{0, 1, 2, 3, 5},1023),1.5); + assertEquals(SensorDataConverter.scaleECG(0, new Integer[]{0}, 1023), 1.5); + } + + @Test + public void test_acc_conversion() { + assertEquals(SensorDataConverter.scaleAccelerometer(0, new Integer[]{0}, 0), -4.85); + assertEquals(SensorDataConverter.scaleAccelerometer(5, new Integer[]{1, 2, 3, 5}, 0),-4.85); + assertEquals(SensorDataConverter.scaleAccelerometer(5, new Integer[]{0, 1, 2, 3, 5}, 0),-4.85); + assertEquals(SensorDataConverter.scaleAccelerometer(5, new Integer[]{0, 1, 2, 3, 5}, 63),4.85); + assertEquals(SensorDataConverter.scaleAccelerometer(3, new Integer[]{0, 1, 2, 3, 5},1023),4.99); + assertEquals(SensorDataConverter.scaleAccelerometer(0, new Integer[]{0}, 1023), 4.99); } @Test public void test_eda_conversion() { - assertEquals(SensorDataConverter.scaleEDA(0, 0), 1.0); - assertEquals(SensorDataConverter.scaleEDA(0, 1023), Double.POSITIVE_INFINITY); + assertEquals(SensorDataConverter.scaleEDA(0, new Integer[]{0}, 0), 0.0); + assertEquals(SensorDataConverter.scaleEDA(5, new Integer[]{1, 2, 3, 5}, 0), 0.0); + assertEquals(SensorDataConverter.scaleEDA(5, new Integer[]{0, 1, 2, 3, 5}, 0), 0.0); + assertEquals(SensorDataConverter.scaleEDA(5, new Integer[]{0, 1, 2, 3, 5}, 63),25.0); + assertEquals(SensorDataConverter.scaleEDA(3, new Integer[]{0, 1, 2, 3, 5},1023),25.0); + assertEquals(SensorDataConverter.scaleEDA(0, new Integer[]{0}, 1023), 25.0); } @Test public void test_luminosity_conversion() { - assertEquals(SensorDataConverter.scaleLuminosity(0, 0), 0.0); - assertEquals(SensorDataConverter.scaleLuminosity(0, 1023), 100.0); + assertEquals(SensorDataConverter.scaleLuminosity(0, new Integer[]{0}, 0), 0.0); + assertEquals(SensorDataConverter.scaleLuminosity(5, new Integer[]{1, 2, 3, 5}, 0), 0.0); + assertEquals(SensorDataConverter.scaleLuminosity(5, new Integer[]{0, 1, 2, 3, 5}, 0), 0.0); + assertEquals(SensorDataConverter.scaleLuminosity(5, new Integer[]{0, 1, 2, 3, 5}, 63),100.0); + assertEquals(SensorDataConverter.scaleLuminosity(3, new Integer[]{0, 1, 2, 3, 5},1023),100.0); + assertEquals(SensorDataConverter.scaleLuminosity(0, new Integer[]{0}, 1023), 100.0); } @Test public void test_tmp_celsius_conversion() { - assertEquals(SensorDataConverter.scaleTMP(0, 0, true), -50.0); - assertEquals(SensorDataConverter.scaleTMP(0, 1023, true), 280.0); + assertEquals(SensorDataConverter.scaleTMP(0, new Integer[]{0}, 0, true), -50.0); + assertEquals(SensorDataConverter.scaleTMP(5, new Integer[]{1, 2, 3, 5}, 0, true), -50.0); + assertEquals(SensorDataConverter.scaleTMP(5, new Integer[]{0, 1, 2, 3, 5}, 0, true), -50.0); + assertEquals(SensorDataConverter.scaleTMP(5, new Integer[]{0, 1, 2, 3, 5}, 63, true),280.0); + assertEquals(SensorDataConverter.scaleTMP(3, new Integer[]{0, 1, 2, 3, 5},1023, true),280.0); + assertEquals(SensorDataConverter.scaleTMP(0, new Integer[]{0}, 1023, true), 280.0); } @Test public void test_tmp_fahrenheit_conversion() { - assertEquals(SensorDataConverter.scaleTMP(0, 0, false), -58.0); - assertEquals(SensorDataConverter.scaleTMP(0, 1023, false), 536.0); + assertEquals(SensorDataConverter.scaleTMP(0, new Integer[]{0},0, false), -58.0); + assertEquals(SensorDataConverter.scaleTMP(5, new Integer[]{1, 2, 3, 5},0, false), -58.0); + assertEquals(SensorDataConverter.scaleTMP(5, new Integer[]{0, 1, 2, 3, 5},0, false), -58.0); + assertEquals(SensorDataConverter.scaleTMP(5, new Integer[]{0, 1, 2, 3, 5}, 63, false),536.0); + assertEquals(SensorDataConverter.scaleTMP(3, new Integer[]{0, 1, 2, 3, 5},1023, false),536.0); + assertEquals(SensorDataConverter.scaleTMP(0, new Integer[]{0},1023, false), 536.0); } @Test public void test_pzt_conversion() { - assertEquals(SensorDataConverter.scalePZT(0, 0), -50.0); - assertEquals(SensorDataConverter.scalePZT(0, 1023), 50.0); + assertEquals(SensorDataConverter.scalePZT(0, new Integer[]{0},0), -50.0); + assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{1, 2, 3, 5},0), -50.0); + assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{0, 1, 2, 3, 5},0), -50.0); + assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{0, 1, 2, 3, 5}, 63),50.0); + assertEquals(SensorDataConverter.scalePZT(3, new Integer[]{0, 1, 2, 3, 5},1023),50.0); + assertEquals(SensorDataConverter.scalePZT(0, new Integer[]{0},1023), 50.0); } @Test public void test_EEG_conversion() { - assertEquals(SensorDataConverter.scaleEEG(0, 0), -41.25); - assertEquals(SensorDataConverter.scaleEEG(0, 1023), 41.25); + assertEquals(SensorDataConverter.scaleEEG(0, new Integer[]{0}, 0), -39.49); + assertEquals(SensorDataConverter.scaleEEG(5, new Integer[]{1, 2, 3, 5}, 0), -39.49); + assertEquals(SensorDataConverter.scaleEEG(5, new Integer[]{0, 1, 2, 3, 5}, 0), -39.49); + assertEquals(SensorDataConverter.scaleEEG(5, new Integer[]{0, 1, 2, 3, 5}, 63),39.49); + assertEquals(SensorDataConverter.scaleEEG(3, new Integer[]{0, 1, 2, 3, 5},1023),39.49); + assertEquals(SensorDataConverter.scaleEEG(0, new Integer[]{0}, 1023), 39.49); } } From 3e9a7a461ed68e10e2050348449f996d3a99fe66 Mon Sep 17 00:00:00 2001 From: "G. Ramos" Date: Thu, 26 Aug 2021 11:24:50 +0100 Subject: [PATCH 2/2] Update of the BITalino Respiration Sensor Transfer Function --- .../java/com/bitalino/util/SensorDataConverter.java | 6 +++--- .../com/bitalino/util/SensorDataConverterTest.java | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bitalino/util/SensorDataConverter.java b/src/main/java/com/bitalino/util/SensorDataConverter.java index 7c244e6..03dd0ea 100644 --- a/src/main/java/com/bitalino/util/SensorDataConverter.java +++ b/src/main/java/com/bitalino/util/SensorDataConverter.java @@ -91,7 +91,7 @@ public static double scaleECG(final int port, final Integer[] activePorts, final * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. - * @return a value ranging between -3 and 3g + * @return a value ranging between -4.85 and 4.85g (6 bits) or between -4.85 and 4.99 (10 bits). */ public static double scaleAccelerometer(final int port, final Integer[] activePorts, final int raw) { final double result = scaleAccelerometerWithPrecision(port, activePorts, raw); @@ -188,10 +188,10 @@ public static double scaleTMP(final int port, final Integer[] activePorts, final * available ports are active the array should be {0, 1, 2, 3, 4, 5}. * @param raw * the value read. - * @return a value ranging between -50% and 50% + * @return a value ranging between -1.65V and 1.65V */ public static double scalePZT(final int port, final Integer[] activePorts, final int raw){ - double result = ((raw/getResolution(port, activePorts)) - 0.5)*100; + double result = ((raw/getResolution(port, activePorts)) - 0.5)*VCC; return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP) .doubleValue(); diff --git a/src/test/java/com/bitalino/util/SensorDataConverterTest.java b/src/test/java/com/bitalino/util/SensorDataConverterTest.java index 1b53770..b888d8d 100644 --- a/src/test/java/com/bitalino/util/SensorDataConverterTest.java +++ b/src/test/java/com/bitalino/util/SensorDataConverterTest.java @@ -102,12 +102,12 @@ public void test_tmp_fahrenheit_conversion() { @Test public void test_pzt_conversion() { - assertEquals(SensorDataConverter.scalePZT(0, new Integer[]{0},0), -50.0); - assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{1, 2, 3, 5},0), -50.0); - assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{0, 1, 2, 3, 5},0), -50.0); - assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{0, 1, 2, 3, 5}, 63),50.0); - assertEquals(SensorDataConverter.scalePZT(3, new Integer[]{0, 1, 2, 3, 5},1023),50.0); - assertEquals(SensorDataConverter.scalePZT(0, new Integer[]{0},1023), 50.0); + assertEquals(SensorDataConverter.scalePZT(0, new Integer[]{0},0), -1.65); + assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{1, 2, 3, 5},0), -1.65); + assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{0, 1, 2, 3, 5},0), -1.65); + assertEquals(SensorDataConverter.scalePZT(5, new Integer[]{0, 1, 2, 3, 5}, 63),1.65); + assertEquals(SensorDataConverter.scalePZT(3, new Integer[]{0, 1, 2, 3, 5},1023),1.65); + assertEquals(SensorDataConverter.scalePZT(0, new Integer[]{0},1023), 1.65); } @Test