From 4ec9b4bd0c50d31f0eb4b89745eeac0d86bb72e7 Mon Sep 17 00:00:00 2001 From: Adam Serbinski <37986043+ASerbinski@users.noreply.github.com> Date: Sun, 10 Oct 2021 05:05:35 -0400 Subject: [PATCH] Update calculations for OneByone scales (#747) * Update calculations for OneByone scales Previously, the value reported for muscle mass was lean body mass less skeletal mass. This was not a correct report for muscle mass since it included additional values, such as organs and skin mass. In addition, the impedance value previously used was incorrect. There were, in fact, two different calculations being performed for impedance based on data fields that were not relevant to it, therefore the value for impedance was entirely incorrect, jumpy, and unpredictable. In fact, the correct bytes for impedance are the second and third bytes in the data packet received from the scale, which produces correct and reasonable impedance values. This commit corrects the prior errors, provides a calculation for lean body mass, and calculates muscle mass based on the Janssen formula; https://journals.physiology.org/doi/pdf/10.1152/jappl.2000.89.2.465 * Muscle mass should be percent of total body weight, not absolute kg --- .../core/bluetooth/BluetoothOneByone.java | 12 +++--- .../core/bluetooth/lib/OneByoneLib.java | 38 ++++++------------- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOneByone.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOneByone.java index d5a83195..280b273a 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOneByone.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothOneByone.java @@ -145,9 +145,8 @@ public class BluetoothOneByone extends BluetoothCommunication { private void parseBytes(byte[] weightBytes) { float weight = Converters.fromUnsignedInt16Le(weightBytes, 3) / 100.0f; - int impedanceCoeff = Converters.fromUnsignedInt24Le(weightBytes, 5); - int impedanceValue = weightBytes[5] + weightBytes[6] + weightBytes[7]; - boolean impedancePresent = (weightBytes[9] != 1) && (impedanceCoeff != 0); + float impedanceValue = ((float)(((weightBytes[2] & 0xFF) << 8) + (weightBytes[1] & 0xFF))) * 0.1f; + boolean impedancePresent = (weightBytes[9] != 1) && (impedanceValue != 0); boolean dateTimePresent = weightBytes.length >= 18; if (!impedancePresent || (!dateTimePresent && historicMeasurement)) { @@ -166,7 +165,7 @@ public class BluetoothOneByone extends BluetoothCommunication { final ScaleUser scaleUser = OpenScale.getInstance().getSelectedScaleUser(); Timber.d("received bytes [%s]", byteInHex(weightBytes)); - Timber.d("received decrypted bytes [weight: %.2f, impedanceCoeff: %d, impedanceValue: %d]", weight, impedanceCoeff, impedanceValue); + Timber.d("received decoded bytes [weight: %.2f, impedanceValue: %f]", weight, impedanceValue); Timber.d("user [%s]", scaleUser); int sex = 0, peopleType = 0; @@ -203,11 +202,12 @@ public class BluetoothOneByone extends BluetoothCommunication { dateTime.setLenient(false); scaleBtData.setDateTime(dateTime.getTime()); - scaleBtData.setFat(oneByoneLib.getBodyFat(weight, impedanceCoeff)); + scaleBtData.setFat(oneByoneLib.getBodyFat(weight, impedanceValue)); scaleBtData.setWater(oneByoneLib.getWater(scaleBtData.getFat())); scaleBtData.setBone(oneByoneLib.getBoneMass(weight, impedanceValue)); scaleBtData.setVisceralFat(oneByoneLib.getVisceralFat(weight)); - scaleBtData.setMuscle(oneByoneLib.getMuscle(weight, scaleBtData.getFat(), scaleBtData.getBone())); + scaleBtData.setMuscle(oneByoneLib.getMuscle(weight, impedanceValue)); + scaleBtData.setLbm(oneByoneLib.getLBM(weight, scaleBtData.getFat())); Timber.d("scale measurement [%s]", scaleBtData); diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/lib/OneByoneLib.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/lib/OneByoneLib.java index 2bff5485..8edfdc40 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/lib/OneByoneLib.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/lib/OneByoneLib.java @@ -33,8 +33,12 @@ public class OneByoneLib { return weight / (((height * height) / 100.0f) / 100.0f); } - public float getMuscle(float weight, float bodyFat, float boneMass) { - return (weight - ((bodyFat / 100.0f) * weight)) - boneMass; + public float getLBM(float weight, float bodyFat) { + return weight - (bodyFat / 100.0f * weight); + } + + public float getMuscle(float weight, float impedanceValue){ + return (float)((height * height / impedanceValue * 0.401) + (sex * 3.825) - (age * 0.071) + 5.102) / weight * 100.0f; } public float getWater(float bodyFat) { @@ -50,7 +54,7 @@ public class OneByoneLib { return coeff * water; } - public float getBoneMass(float weight, int impedanceValue) { + public float getBoneMass(float weight, float impedanceValue) { float boneMass, sexConst , peopleCoeff = 0.0f; switch (peopleType) { @@ -173,30 +177,12 @@ public class OneByoneLib { } } - public float getBodyFat(float weight, int impedanceCoeff) { - float impedanceValue, bodyFatConst=0; + public float getBodyFat(float weight, float impedanceValue) { + float bodyFatConst=0; - if (impedanceCoeff == 0x0FFFFFF) { - return 1.0f; - } - - impedanceValue = (float)(((impedanceCoeff & 0x0FF0000) >> 0x10) + (impedanceCoeff & 0x0F00) - ((impedanceCoeff & 0x0F000) >> 0xC) + (0 - (impedanceCoeff & 0xFF)) * 4) * 0.5f; - - if (50.0f <= impedanceValue) { - if (impedanceValue > 3000.0f) { - bodyFatConst = 0.0068f; - } else { - if (200.0f > impedanceValue) { - bodyFatConst = 1.36f; - } else { - if (impedanceValue > 1200) { - bodyFatConst = 8.16f; - } else { - bodyFatConst = 0.0068f * impedanceValue; - } - } - } - } + if (impedanceValue >= 1200.0f) bodyFatConst = 8.16f; + else if (impedanceValue >= 200.0f) bodyFatConst = 0.0068f * impedanceValue; + else if (impedanceValue >= 50.0f) bodyFatConst = 1.36f; float peopleTypeCoeff, bodyVar, bodyFat;