How to convert IEEE-11073 16-bit SFLOAT to simple float in Java?

11,276

Solution 1

You can use bit shifting. extract the sign, exponent and mantissa and shift these so they are in float format. You may need to correct for Infinity and NaN.

As @PretiP's answer points out the exponent is base 10 so you would need to multiply or divide by a power of 10 to get the final value.

Solution 2

IEEE-11073 is not in public domain but you can find suffcient information in bluetooth personal health profiles. Google up with full spec# 11073-2060. Following is copy paste from a bluetooth personal health transcoding paper:

The following information is defined in ISO/IEEE Std. 11073-2060™1-2008 [1]. The SFLOAT-Type data type is defined to represent numeric values that are not integer in type. The SFLOAT-Type is defined as a 16-bit value with 12-bit mantissa and 4-bit exponent. See Annex F.8 of [1] for a thorough definition of the SFLOAT-Type. This data type is defined as follows: Exponent Mantissa Size 4 bit 12 bit

16-bit float type; the integer type is a placeholder only

SFLOAT-Type ::= INT-U16 The 16–bit value contains a 4-bit exponent to base 10, followed by a 12-bit mantissa. Each is in twos-complement form. Special values are assigned to express the following: NaN [exponent 0, mantissa +(2^11 –1) → 0x07FF] NRes [exponent 0, mantissa –(2^11) → 0x0800] + INFINITY [exponent 0, mantissa +(2^11 –2) → 0x07FE] – INFINITY [exponent 0, mantissa –(2^11 –2) → 0x0802] Reserved for future use [exponent 0, mantissa –(2^11 –1) → 0x0801]

Solution 3

This 11073 library has C code that does that:

https://github.com/signove/antidote/blob/master/src/util/bytelib.c

Should not be difficult to convert to Java.

double read_sfloat(ByteStreamReader *stream, int *error)
{
    intu16 int_data = read_intu16(stream, error);
    if (*error)
        return 0;

    intu16 mantissa = int_data & 0x0FFF;
    int8 expoent = int_data >> 12;

    if (expoent >= 0x0008) {
        expoent = -((0x000F + 1) - expoent);
    }

    float output = 0;

    if (mantissa >= FIRST_S_RESERVED_VALUE && mantissa
        <= MDER_S_NEGATIVE_INFINITY) {
        output = reserved_float_values[mantissa
                           - FIRST_S_RESERVED_VALUE];
    } else {
        if (mantissa >= 0x0800) {
            mantissa = -((0x0FFF + 1) - mantissa);
        }
        double magnitude = pow(10.0f, expoent);
        output = (mantissa * magnitude);
    }

    return output;
}

The boilerplate code:

typedef enum {
    MDER_S_POSITIVE_INFINITY = 0x07FE,
    MDER_S_NaN = 0x07FF,
    MDER_S_NRes = 0x0800,
    MDER_S_RESERVED_VALUE = 0x0801,
    MDER_S_NEGATIVE_INFINITY = 0x0802
} ReservedSFloatValues;

static const intu32 FIRST_S_RESERVED_VALUE = MDER_S_POSITIVE_INFINITY;

intu16 read_intu16(ByteStreamReader *stream, int *error)
{
    intu16 ret = 0;

    if (stream && stream->unread_bytes > 1) {
        ret = ntohs(*((uint16_t *) stream->buffer_cur));

        stream->buffer_cur += 2;
        stream->unread_bytes -= 2;
    } else {
        if (error) {
            *error = 1;
        }

        ERROR("read_intu16");
    }

    return ret;
}

Solution 4

Try searching for "Personal Health Devices Transcoding_WP_V11" and it will lead you to a document from the Bluetooth Special Interest Group. In the 25 Oct 2011 / V11r00 version of the document, section 2.2 "TRANSCODING BLUETOOTH CHARACTERISTICS TO 11073 ATTRIBUTES" gives a detailed explanation and examples of how to deal with 11073-20601 FLOAT (32 bit) and SFLOAT (16 bit) numbers.

The current URL of this document is https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=242961

Note that this is likely the same document Petri P. is referencing above.

Solution 5

Even that this post is a little bit old, I just want to post my solution, based on this java file.

public short getExponent(short value)
{
    if (value < 0)
    { // if exponent should be negative
        return (byte) (((value >> 12) & 0x0F) | 0xF0);
    }
    return (short) ((value >> 12) & 0x0F);
}

public short getMantissa(short value)
{
    if ((value & 0x0800) != 0)
    { // if mantissa should be negative
        return (short) ((value & 0x0FFF) | 0xF000);
    }
    return (short) (value & 0x0FFF);
}

public double parseSFLOATtoDouble(short value)
{
    // NaN
    if (value == 0x07FF)
    {
        return Double.NaN;
    }
    // NRes (not at this resolution)
    else if (value == 0x0800)
    {
        return Double.NaN;
    }
    // +INF
    else if (value == 0x07FE)
    {
        return Double.POSITIVE_INFINITY;
    }
    // -INF
    else if (value == 0x0802)
    {
        return Double.NEGATIVE_INFINITY;
    }
    // Reserved
    else if (value == 0x0801)
    {
        return Double.NaN;
    }
    else
    {
        return ((double) getMantissa(value)) * Math.pow(10, getExponent(value));
    }
}
Share:
11,276
SharkyLV
Author by

SharkyLV

Updated on June 12, 2022

Comments

  • SharkyLV
    SharkyLV almost 2 years

    The title speaks for itself: How to convert IEEE-11073 16-bit SFLOAT to simple float in Java?