All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.utils.MilStd1750A Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.utils;

/**
 * Some Mil1750A encoding/decoding functions.
 * 
 * http://www.mssl.ucl.ac.uk/swift/docs/mil-std-1750a.pdf
 * 
 * @author nm
 *
 */
public class MilStd1750A {
    public static long MAX_FLOAT_VALUE = 0x7FFFFF_7F_FFFFL;
    public static long MIN_FLOAT_VALUE = 0xFFFFFF_7F_FFFFL;
    public static int MAX_FLOAT32_VALUE = 0x7FFFFF_7F;
    public static int MIN_FLOAT32_VALUE = 0xFFFFFF_7F;

    /**
     * Encode double value to 48 bits 1750A floating point number.
     * If the number is too large or too small, the {@link #MAX_FLOAT_VALUE} respectively {@link #MIN_FLOAT_VALUE} are
     * returned
     * 
     * This performs some bit operations to transform from IEEE 754 binary representation to STD 1750 binary
     * representation.
     * No Math.pow or other expensive operations are used.
     * 
     * @param value
     *            - double number
     * @return encoded 48 bits number (the first 16 bits of the long are 0)
     */
    public static long encode48(double value) {

        long x = Double.doubleToRawLongBits(value);
        if (x == 0) {
            return 0;
        }

        // IEEE 754 numbers have an implicit 1 in front of the mantissa (that's why we do the "| 0x10...")
        // MILSTD don't so automatically we increase the exponent with 1
        // you know of course that the IEEE 754 exponents are biased with 1023 and 1023-1=1022 :)
        int e = (int) (((x >> 52) & 0x7FF) - 1022);
        long m = (x & 0xF_FFFF_FFFF_FFFFL) | 0x10_0000_0000_0000L;

        if (x < 0) {
            // this is a negative number, however in IEEE 754 the sign is at the beginning of the number and the
            // mantissa is positive
            // in the MILSTD we have to encode the sign in the mantissa
            // the trick is that we know there is a 1 in front of the mantissa (we added it above) - therefore when we
            // change sign (m=-m) the first digit will become 0 - that is true in all cases with one exception
            if (m == 0x10_0000_0000_0000L) {
                // exception: when we change sign this mantissa stays the same
                // that means there will be two binary 1 (the sign plus the first bit of the mantissa) at the beginning
                // of the MILSTD number which is not allowed.
                // therefore we shift it to the left and decrease the exponent
                m = m << 1;
                e--;
            }
            m = -m;
        } // for positive numbers we do nothing because the mantissa is already normalised
          // (first bit = sign = 0, second bit = implicit IEEE = 1)

        if (e > 127) {
            return x > 0 ? MAX_FLOAT_VALUE : MIN_FLOAT_VALUE;
        } else if (e < -128) {
            return 0;
        }
        m = m >> 14;

        return ((m << 8) & 0xFFFFFF_00_0000L) | ((e << 16) & 0xFF_0000) | (m & 0xFFFF);
    }

    /**
     * Decodes a MIL-STD 1750A 48 bit number into a double.
     * 
     * @param milstd
     *            - number to be decoded. Only the last 48 bits are considered, the first 16 are ignored.
     * @return - the decoded value
     */
    public static double decode48(long milstd) {
        long m = ((milstd >> 8) & 0xFFFFFF_0000L) | (milstd & 0xFFFF);
        if (m == 0) {
            return 0;
        }

        // we convert the MILSTD exponent to byte such that it can become negative and then add the IEEE bias
        long e = (byte) (milstd >> 16) + 1023;

        long sign = (m >> 39) << 63;

        if (sign != 0) {
            m = (-m) & 0xFFFFFFFFFFL;
        }
        // we have to find the first bit 1 from the left
        // and shift m such that the first bit becomes the implicit 1 of IEEE
        int k = Long.numberOfLeadingZeros(m) - 24;
        m = m << (13 + k);
        e = e - k;

        long l = sign | (e << 52) | (m & 0xF_FFFF_FFFF_FFFFL);
        return Double.longBitsToDouble(l);
    }

    /**
     * Encodes a double into a MIL-STD 1750A 32 bit number.
     * 
     * If the number to be encoded is too large or too small,
     * the {@link #MAX_FLOAT32_VALUE} respectively {@link #MIN_FLOAT32_VALUE} are returned
     * 
     * @param value
     * @return
     */
    public static int encode32(double value) {
        return (int) (encode48(value) >> 16);
    }

    /**
     * 
     * Decodes a 32 bit MIL-STD 1750A number into a double.
     * 
     * @param milstd
     * @return
     */
    public static double decode32(int milstd) {
        return decode48(((long) milstd) << 16);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy