embeddedaccelerometerzephyr-rtos

Converting accelerometer value to m/s^2


I'm trying to understand the method to convert raw accelerometer's output to m/s^2 Suppose I'm using ADXL345:

Supposed that the value I got for Z axe is 36. I would do the following math to convert it to m/s^2:

val = (36 * 31.2) = 1123,2mg -> 1,123g
valms = val * 9.81m/s^2 = 1,123g * 9.81m/s^2 = 11,01663m/s^2

whereas in the Zephyr's code the formula is as follows:

static void adxl345_accel_convert(struct sensor_value *val, int16_t sample)
{
    if (sample & BIT(9)) {
        sample |= ADXL345_COMPLEMENT;
    }

    val->val1 = ((sample * SENSOR_G) / 32) / 1000000;
    val->val2 = ((sample * SENSOR_G) / 32) % 1000000;
}

val->val1 -> is integral part

val->val2 -> is fractional part

SENSOR_G is 9806650LL micro m/s^2

Let's skip the fractional part for now.

I cannot understand why sample is multiplied by SENSOR_G and then divided by 32? Why 32? I suspect that maybe it's rounded scaling factor? But why is this divided by scaling factor? I cannot wrap my head around it.

Anyway both calculations provide roughly the same output. Perhaps the Zephyr's version is more accurate?


Solution

  • I believe your confusion stems from the fact that 32 * 32 == 1024, and also that the calculations involve g and mg which differ by a factor of 1000.

    It just so happens that multiplying by 32 and then dividing by 1000 is the approximate same as dividing by 32.

    i.e. 1 / 32 == 32/1024

    In your calculation you multiply by 31.2 then divide by 1000 to get a value measured in g. (This is effectively the same as dividing by 32.) You then multiply by g to get m/s^2.

    In the Zephyr code, they just combine the multiply by 31.2 and the divide by 1000 into a single divide by 32.

    You only get this coincidence for 32/LSB because 32 happens to square to ~1000. For other resolutions, this wouldn't be the case, and it would probably be less confusing.