Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 69 additions & 43 deletions src/main/java/com/bitalino/util/SensorDataConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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();
}
Expand All @@ -57,31 +65,36 @@ public static double scaleEMG(final int port, final int raw) {
*
* @param port
* the port where the <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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();
}

/**
* 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 <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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 -4.85 and 4.85g (6 bits) or between -4.85 and 4.99 (10 bits).
*/
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();
}
Expand All @@ -91,16 +104,17 @@ public static double scaleAccelerometer(final int port, final int raw) {
*
* @param port
* the port where the <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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;
}

Expand All @@ -109,48 +123,52 @@ public static double scaleAccelerometerWithPrecision(final int port,
*
* @param port
* the port where the <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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;
}

/**
* Luminosity conversion.
*
* @param port
* the port where the <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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));
}

/**
* Temperature conversion.
*
* @param port
* the port where the <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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
* <tt>true</tt>:use celsius as metric,
* <tt>false</tt>: 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
Expand All @@ -165,12 +183,15 @@ public static double scaleTMP(final int port, final int raw, boolean celsius){
*
* @param port
* the port where the <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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%
* @return a value ranging between -1.65V and 1.65V
*/
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)*VCC;
return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP)
.doubleValue();

Expand All @@ -181,15 +202,16 @@ public static double scalePZT(final int port, final int raw){
*
* @param port
* the port where the <tt>raw</tt> value was read from.
* @param activePorts
* array containing the list of active <tt>ports</tt>, 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)
Expand All @@ -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 <tt>ports</tt>, 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;
}

}
74 changes: 58 additions & 16 deletions src/test/java/com/bitalino/util/SensorDataConverterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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), -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
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);
}

}