BINEX Conventions

*Binary Exchange format for GPS/GNSS*
*Data/Metadata/Ephemerides/Orbits/Solutions*

**BINEX** 0x7f-00 -> **RINEX**)
would result in an error of 0.001 in the **RINEX** from what would have
been obtained if we had started with the original floating-point value
and done "single rounding" (i.e. floating-point value -> **RINEX**).

**Index:**

**BINEX** homepage

text representation of numbers in **BINEX** documentation

Definitions of terms used in **BINEX** documentation

unsigned **BINEX** 1-4 byte integer details

modified signed GFZ 1, 2, 4, or 8 byte integer details

modified signed GFZ 1-8 byte integer details

1-byte satellite ID details

**BINEX** to **RINEX** considerations

**Contact:** UNAVCO data guru

*Text Representation of Numbers:*

**decimal**:
All numbers written without special notation should be assumed to
be in ordinary base-10 representation, i.e. "11" means eleven; the
most significant digits are to the left, as usual

**hexidecimal**:
All numbers preceeded by the notation "0x" should be assumed to
be in hexidecimal base-16 representation, i.e. 0x11 = 17 and means seventeen;
the most significant digits are to the left, as usual; 0x00 = 0, ..., 0x09 = 9,
0x0a = 10, ..., 0x0f = 15, 0x10 = 16, and so on

**binary**:
To show the actual binary structure of certain bytes, all 0/1 numbers
bracketed by square brackets, [ ], in groups of 8 should be assumed to
represent a byte in binary base-2 representation, i.e. [00000011] = 0x03 = 3;
the most significant digits (bits) are to the left in each set of brackets

Furthermore, to describe specific bits, the bit numbering starts at 0 for
the least significant bit (LSB). Bit 7 would be the most significant bit (MSB)
of any 8-bit byte.

**endian**:
To represent multi-byte values, two byte orders are allowed in **BINEX**. One is
"big-endian" in which the * most* significant bytes are stored first
(i.e. at the lowest memory/storage address), and "little-endian" in which the

**byte_order**:
To represent the actual byte order in part of a file or data stream, two-digit
hexadecimal numbers are used, sans the leading "0x", for each byte and separating
bytes with an underscore, with the first occurring bytes being to the left.
For example, the 8-byte floating-point number 23456789.012 would show up as
41_76_5e_c1_50_31_26_e9 in a big-endian record and as
e9_26_31_50_c1_5e_76_41 in a little-endian record
using the ANSI/IEEE Std 754-1985 format
(i.e. in this case, 0x41 is the most significant byte, with bit 7 being the sign bit, being = 0 in this case)
(this would be the order of bytes if using UNIX "od -x" or "od -t x1" to
display the byte values--but be careful!: Executing "od -x" on little-endian UNIX systems
may read in two-byte words and then display the byte-swapped result. Then use
"od -t x1" instead.)

**record**: the largest granularity of
a **BINEX** file or data stream, made up of the generalized
record structure; each record has its own unique identification
(ID) number

**subrecord**:
a specific type of **BINEX** record interpretation
for certain record IDs; if a particular **BINEX** record has subrecord
designations, only one subrecord per record is allowed; basically, the
mechanism of sub-defining a record; a notation of 0x7f-00 may be used to
indicate record 0x7f, subrecord 0x00

**field**:
a specific component of a **BINEX** record for certain record IDs;
if a particular **BINEX** record has field designations, multiple fields
per record are allowed; a good example of a record with fields is
record 0x00 for site metadata

**sint1**:
a 1-byte signed integer stored as two's complement, having a value of -128 (= 0x80) to +127 (= 0x7f)

**sint2**:
a 2-byte signed integer stored as two's complement, having a value of -32768 (= 0x8000) to +32767 (= 0x7fff)

**sint4**:
a 4-byte signed integer stored as two's complement, having a value of -2147483648 (= 0x80000000) to +2147483647 (= 0x7fffffff)

**2c Nb**:

**s+ Nb**:

**uint1**:
a 1-byte unsigned integer, having a value of 0 (= 0x00) to 255 (= 0xff)

**uint2**:
a 2-byte unsigned integer, having a value of 0 (= 0x0000) to 65535 (= 0xffff)

**uint4**:
a 4-byte unsigned integer, having a value of 0 (= 0x00000000) to 4294967295 (= 0xffffffff)

**u Nb**:

**real4**:
a 4-byte floating-point representation, stored according to ANSI/IEEE Std 754-1985

**real8**:
a 8-byte floating-point representation, stored according to ANSI/IEEE Std 754-1985

**ubnxi**:
(pronounced "YOU-bin-ox-ee")
an unsigned integer stored using 1, 2, 3, or 4 bytes to present integers of 0 to 536870911,
used to represent **BINEX** record IDs, subrecord IDs, field IDs, and so on.
See details for more information.

**mGFZi**:
(pronounced "mug-FUZZ-ee")
a signed integer stored using 1, 2, 4, or 8 bytes to present integers of about -1.15292e18 to +1.15292e18
using a modified version of a compression scheme developed by GFZ, plus using "special" numbers to
flag certain conditions, such as using the 1-byte mGFZi to store "-0" to mean "no value".
See details for more information.

**mGFZI**:
(pronounced "mug-FUZZ-ee")
a signed integer stored using 1, 2, 3, 4, 5, 6, 7, or 8 bytes to present integers of about -1.15292e18 to +1.15292e18
using a modified version of a compression scheme developed by GFZ, plus using "special" numbers to
flag certain conditions, such as using the 1-byte mGFZI to store "-0" to mean "no value".
See details for more information.

**SVid1**:
1 byte used to encode the satellite system and related satellite number; can be
used for up to 8 satellite systems (currently defined for
NAVSTAR GPS,
GLONASS,
SBAS,
Galileo,
Beidou-2/Compass,
and
QZSS);
however the corresponding satellite ID number must be in the range of 1-32.
See details for more information.

*Unsigned BINEX 1-4 byte integer:*

The following algorithm is used to store unsigned integers from 0 to 536870911. This was developed to store the

The algorithm is as follows. The first byte has the high-bit set aside as an indicator of whether an additional byte needs to be read to extract the final unsigned integer value:

- bit 7 = 0: don't read any more bytes for this integer value
- bit 7 = 1: read next byte and evaluate

There are then four possible type of byte sequences possible:

- 1 byte; [0xxxxxxx] = values of 0-127
- 2 bytes; [1xxxxxxx][0xxxxxxx] = values of 128-16383
- 3 bytes; [1xxxxxxx][1xxxxxxx][0xxxxxxx] = values of 16384-2097151
- 4 bytes; [1xxxxxxx][1xxxxxxx][1xxxxxxx][xxxxxxxx] = values of 2097152-536870911

Examples:

7f_81_7f_....: First byte is 0x7f = [01111111], with bit 7 = 0, so the final value is 0x7f = 127 (don't
read any more bytes).

83_7a_00_....: First byte is 0x83 = [10000011], with bit 7 = 1, therefore examine the next byte.
Second byte is 0x7a = [01111010], with bit 7 = 0 (so don't read a third byte).
The value interpretation depends on whether this is from a big-endian or little-endian **BINEX** record:

- If part of a big-endian record, the masked and shifted bit pattern for the integer is [00000001][11111010] = 0x01fa = 506.
- If part of a little-endian record, the masked, shifted, and byte-swapped bit pattern for the integer is [00111101][00000011] = 0x3d03 = 15619

The C/C++ functions *read_ubnxi()* and *ubnxi_to_uint4()* are provided
as prototype code for read a file or stream and interpreting a ubnxi
as a uint4.
The C/C++ funtion *uint4_to_ubnxi()* is provided as prototype code for converting
a uint4 to a ubnxi
and storing the result at a uint1 pointer.

*Modified signed GFZ 1, 2, 4, or 8 byte integer:*

The original GFZ algorithm for storing a signed integer in 1, 2, 4 or 8 bytes is:

- leading byte = [xxxxxx00] is for 0 to +63, absolute value in 6 most significant bits (1 byte in total needed)
- leading byte = [xxxxxx10] is for 0 to -63, absolute value in 6 most significant bits (1 byte in total needed)
- leading byte = [xxxxx001] is for 0 to +8191, absolute value in 5 most significant bits of this byte plus 8 bits of next byte (2 bytes in total needed)
- leading byte = [xxxxx101] is for 0 to -8191, absolute value in 5 most significant bits of this byte plus 8 bits of next byte (2 bytes in total needed)
- leading byte = [xxxx0011] is for 0 to +268435455, absolute value in 4 most significant bits of this byte plus 24 bits of next three bytes (4 bytes in total needed)
- leading byte = [xxxx1011] is for 0 to -268435455, absolute value in 4 most significant bits of this byte plus 24 bits of next three bytes (4 bytes in total needed)
- leading byte = [xxxx0111] is for 0 to +(2^60 - 1), absolute value in 4 most significant bits of this byte plus 56 bits of next seven bytes (8 bytes in total needed)
- leading byte = [xxxx1111] is for 0 to -(2^60 - 1), absolute value in 4 most significant bits of this byte plus 56 bits of next seven bytes (8 bytes in total needed)

For **BINEX**, this algorithm is modified to get a bit more compression, to
allow for special values, and to allow for little- and big-endian records.
In a little-endian record:

- leading byte = [xxxxxx00] is for 0 to +63, absolute value in 6 most significant bits (1 byte in total needed)
- leading byte = [xxxxxx10] is for -1 to -63, absolute value in 6 most significant bits (1 byte in total needed)
- leading byte = [00000010] = 0x02 (value of "-0" in the original GFZ algorithm) is reserved to mean "no valid data"
- leading byte = [xxxxx001] is for +64 to +8253, absolute value - 62 in 5 most significant bits of this byte plus 8 bits of next byte (2 bytes in total needed)
- leading byte = [xxxxx101] is for -64 to -8253, absolute value - 62 in 5 most significant bits of this byte plus 8 bits of next byte (2 bytes in total needed)
- leading bytes of [000001101] = 0x0d, [00000101] = 0x05, [00000001] = 0x01, [00001001] = 0x09 (values of "-1", "-0", "+0", and "+1" in the original GFZ algorithm) are reserved
- leading byte = [xxxx0011] is for +8254 to +268443708, absolute value - 8253 in 4 most significant bits of this byte plus 24 bits of next three bytes (4 bytes in total needed)
- leading byte = [xxxx1011] is for -8254 to -268443708, absolute value - 8253 in 4 most significant bits of this byte plus 24 bits of next three bytes (4 bytes in total needed)
- leading byte = [xxxx0111] is for +268443709 to +(2^60 - 1 + 268443708), absolute value - 268443708 in 4 most significant bits of this byte plus 56 bits of next seven bytes (8 bytes in total needed)
- leading byte = [xxxx1111] is for -268443709 to -(2^60 - 1 + 268443708), absolute value - 268443708 in 4 most significant bits of this byte plus 56 bits of next seven bytes (8 bytes in total needed)

In a big-endian record, the two, three, or four "indicator" bits in the leading record occur as most significant bits (rather than least significant bits) and in reverse order from the little-endian record; the six, five, or four "value" bits in the leading record occur as least significant bits, but only shifted in the byte. Thus, the reserved value of [01000000] = 0x40 means "no valid data":

- leading byte = [00xxxxxx] is for 0 to +63, absolute value in 6 least significant bits (1 byte in total needed)
- leading byte = [01xxxxxx] is for -1 to -63, absolute value in 6 least significant bits (1 byte in total needed)
- leading byte = [01000000] = 0x40 (value of "-0" in the original GFZ algorithm) is reserved to mean "no valid data"
- leading byte = [100xxxxx] is for +64 to +8253, absolute value - 62 in 5 least significant bits of this byte plus 8 bits of next byte (2 bytes in total needed)
- leading byte = [101xxxxx] is for -64 to -8253, absolute value - 62 in 5 least significant bits of this byte plus 8 bits of next byte (2 bytes in total needed)
- leading bytes of [101100000] = 0xb0, [10100000] = 0xa0, [10000000] = 0x80, [10010000] = 0x90 (values of "-1", "-0", "+0", and "+1" in the original GFZ algorithm) are reserved
- leading byte = [1100xxxx] is for +8254 to +268443708, absolute value - 8253 in 4 least significant bits of this byte plus 24 bits of next three bytes (4 bytes in total needed)
- leading byte = [1101xxxx] is for -8254 to -268443708, absolute value - 8253 in 4 least significant bits of this byte plus 24 bits of next three bytes (4 bytes in total needed)
- leading byte = [1110xxxx] is for +268443709 to +(2^60 - 1 + 268443708), absolute value - 268443708 in 4 least significant bits of this byte plus 56 bits of next seven bytes (8 bytes in total needed)
- leading byte = [1111xxxx] is for -268443709 to -(2^60 - 1 + 268443708), absolute value - 268443708 in 4 least significant bits of this byte plus 56 bits of next seven bytes (8 bytes in total needed)

The C/C++ function *binex_extract_mGFZi()* is provided
as prototype code to read a location in a uint1 array as a
modified GFZ integer and return this value as a real8.
The C/C++ function *binex_append_mGFZi()* is provided
as prototype code to convert a real8 value into the nearest
modified GFZ integer and store this in a uint1 array.

*Modified signed GFZ 1-8 byte integer:*

(For the original GFZ algorithm for storing a signed integer in 1, 2, 4 or 8 bytes,
see this.)
For **BINEX**, this algorithm is modified to allow for more compression using 1-8 bytes as needed,
to allow for special values, and to allow for little- and big-endian records. The dynamic range of
the 1 and 2 byte cases are sacrificed a bit to allow for more dynamic range of the indicator bits.
Below, "s" is the sign bit: "0" means positive, "1" means negative.
In a little-endian record, the indicator bits are always lowest 4 least significant bits of the
leading byte:

- leading byte = [xxxxs000], 1 byte, absolute value is < 0x0000000000000010 = 16, "-0" = [00001000] = 0x08 is reserved to mean "no valid data"
- leading byte = [xxxxs001], 2 bytes, absolute value is < 0x000000000000100e = 4110, "-1", "-0", "+0", "+1" are reserved
- leading byte = [xxxxs010], 3 bytes, absolute value is < 0x000000000010100d = 1052685, "-0" is reserved
- leading byte = [xxxxs011], 4 bytes, absolute value is < 0x000000001010100c = 269488140, "-0" is reserved
- leading byte = [xxxxs100], 5 bytes, absolute value is < 0x000000101010100b = 68988964875, "-0" is reserved
- leading byte = [xxxxs101], 6 bytes, absolute value is < 0x000010101010100a = 17661175009290, "-0" is reserved
- leading byte = [xxxxs110], 7 bytes, absolute value is < 0x0010101010101009 = 4521260802379785, "-0" is reserved
- leading byte = [xxxxs111], 8 bytes, absolute value is < 0x1010101010101008, "-0" is reserved

In a big-endian record, the "indicator" bits are always the highest 4 most significant bits of the leading byte, with the same bit order as the little-endian record:

- leading byte = [s000xxxx], 1 byte, absolute value is < 0x0000000000000010 = 16, "-0" = [10000000] = 0x80 is reserved to mean "no valid data"
- leading byte = [s001xxxx], 2 bytes, absolute value is < 0x000000000000100e = 4110, "-1", "-0", "+0", "+1" are reserved
- leading byte = [s010xxxx], 3 bytes, absolute value is < 0x000000000010100d = 1052685, "-0" is reserved
- leading byte = [s011xxxx], 4 bytes, absolute value is < 0x000000001010100c = 269488140, "-0" is reserved
- leading byte = [s100xxxx], 5 bytes, absolute value is < 0x000000101010100b = 68988964875, "-0" is reserved
- leading byte = [s101xxxx], 6 bytes, absolute value is < 0x000010101010100a = 17661175009290, "-0" is reserved
- leading byte = [s110xxxx], 7 bytes, absolute value is < 0x0010101010101009 = 4521260802379785, "-0" is reserved
- leading byte = [s111xxxx], 8 bytes, absolute value is < 0x1010101010101008, "-0" is reserved

The C/C++ function *binex_extract_mGFZI()* is provided
as prototype code to read a location in a uint1 array as a
modified GFZ integer and return this value as a real8.
The C/C++ function *binex_append_mGFZI()* is provided
as prototype code to convert a real8 value into the nearest
modified GFZ integer and store this in a uint1 array.

*1-byte satellite ID:*

A single byte can be used to specify most foreseeable combinations for satellite system
and corresponding satellite number, as long as the number of discreet satellite systems
is eight or less, and the corresponding satellite number can be mapped from 0 to 31.
In this byte, bits 5 and 6 (and in the future bit 7) indicate the satellite system;
the lowest 5 bits indicate the satellite number minus 1.
Using C/C++ syntax:

- satellite system = byte >> 5 & 0x07 (for up to and including 8 systems)
- satellite number = (byte & 0x1f) + 0x01

- 0x00 = NAVSTAR GPS system
- 0x01 = GLONASS system
- 0x02 = WAAS/EGNOS/MSAS geostationary SBAS
- 0x03 = Galileo system
- 0x04 = Beidou-1 or Beidou-2/Compass system
- 0x05 = QZSS system
- other two values reserved

- satellite number = PRN # (1-32) if SV in NAVSTAR GPS
- satellite number = slot # (1-24) if SV in GLONASS
- satellite number = PRN # - 119 if SV in WAAS/EGNOS/MSAS (i.e. PRN # - 120 == byte & 0x1f)
- satellite number = PRN # (1-32) if SV in Galileo (i.e. cannot be used for PRN # > 32)
- (note: satellite number for Beidou system is awaiting definition pending more information)
- satellite number = PRN # - 192 if SV in QZSS (i.e. PRN # - 193 == byte & 0x1f)

*BINEX to RINEX considerations:*

For most cases, conversion of **BINEX** to **RINEX** poses no special problems.
There is one situation, however, that deserves a discussion. This is the
conversion of integer values representing rounded floating-point numbers
(e.g. see mGFZi or mGFZI) back to
floating-point numbers.

An example is the floating-point to integer compression used in record/subrecord 0x7f-00. In 0x7f-00, all floating-point pseudorange values are rounded and stored to the nearest 0.001 meter, and all floating-point phase values are rounded and stored to the nearest 0.0001 cycle, both using (in this case) mGFZI integers, after pre-multiplying the pseudorange values by 1000 and the phase values by 10000. The absolute value of the difference between the original floating point value and the reconstructed value is less than 0.001 meter for all pseudorange values and less than 0.0001 cycle for phase values.

However, **RINEX** format only allows the pseudorange and phase values to be recorded
to the nearest 0.001 meter and 0.001 cycle, respectively. In the case of 0x7f-00 conversion
to RINEX, pseudorange values are recorded exactly as one would expect, since both
have a resolution of 0.001 meters. For phase values, however, there is an
occasional error introduced into the RINEX phase values of +-0.001 cycle.
*This is not due to any error in the corresponding BINEX phase value;*
remember, these are valid to the nearest 0.0001 cycle. This is due to the fact
that we are taking a value rounded to the nearest 0.0001 (

To see how this occurs, consider the floating-point values X.261 - X.262:

floating-point nearest 0.0001 nearest 0.001 round nearest 0.0001 (native format) (BINEX 0x7f-00) (RINEX) to nearest 0.001 X.2613000... X.2613 X.261 X.261 X.2613499... X.2613 X.261 X.261 X.2613500... X.2614 X.261 X.261 X.2614000... X.2614 X.261 X.261 X.2614499... X.2614 X.261 X.261 X.2614500... X.2615 X.261 X.262 X.2615000... X.2615 X.262 X.262 X.2615499... X.2615 X.262 X.262 X.2615500... X.2616 X.262 X.262 X.2616000... X.2616 X.262 X.262So, for all values [X.26145, X.2615), i.e. from X.26145 up to but not including X.2615, this "double rounding" (i.e. floating-point value ->

If the floating-point values are randomly distributed, this rounding error
of 0.001 in **RINEX** would occur in about 1/20 of the phase values, where
the **BINEX** phase value has been stored to the nearest 0.0001 cycle.
In test files, the occurrance has been found to be less than 1/30 of the
phase values.

The important point here is that this is not a property of **BINEX** or
**RINEX**, but occurs when we round a floating-point number to some high
precision, and then round that number again to some lower precision.

The best strategy, for example, to take advantage of the higher precision
of **BINEX** 0x7f-00 phase values over **RINEX**, and to avoid these
types of double-rounding errors when converting some **BINEX** data to **RINEX**,
would be to by-pass **RINEX** altogether by replacing any existing
**RINEX** reader with a direct **BINEX** reader.

Last modified: Tuesday, 15-Jan-2019 21:14:08 UTC

2019