
BINEX
Record structure
Synchronization
Record ID bytes
Record message length
Record message
Record checksum/CRC
Reverse record length
Time stamps
Proposed records
Current records
Forward parsing
Conventions
Record ID 0x00
Record ID 0x01
Record ID 0x7d
Record ID 0x7e
Record ID 0x7f
Log
|
 |
BINEX Conventions
Binary Exchange format for GPS/GLONASS/SBAS
Data/Metadata/Ephemerides/Orbits/Solutions
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
Last modified: 23 Oct 2007
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
least significant bytes are stored first (for any particular multi-byte
value, e.g. 2-byte integer, 8-byte floating point, etc.); see also
whatis.techtarget.com and search on the word [endian],
should arrive at:
and review both "big-endian" and "little-endian".
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.)
Definitions:
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)
2cNb:
N-bit signed integer stored as two's complement, having a range of -2^(N-1) to +2^(N-1) - 1;
if N is 8, 16, or 32 and on an even byte alignment,
instead refer to as sint1, sint2, or sint4 respectively
s+Nb:
N+1 bits, where the MSB is a sign bit (1 = negative, 0 = positive) and the N LSBs represent the magnitude;
"+0" (0 for all bits) indicates a value of zero and
"-0" (1 in the MSB sign bit and 0 for all other bits) indicates an invalid or unknown value;
range of ±(2^N - 1)
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)
uNb:
N bits representing a zero or positive value (i.e. no sign bit, therefore unsigned); range of 0 to 2^N - 1;
if N is 8, 16, or 32 and on an even byte alignment,
instead refer to as uint1, uint2, or uint4 respectively
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 only
NAVSTAR GPS,
GLONASS, and
SBAS
are used) and the corresponding satellite 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 BINEX record ID,
the BINEX record length,
any BINEX subrecord ID,
any BINEX field ID,
and so on, where an unsigned integer value is needed.
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
and so on (if bit 7 = 1) for the second and third bytes if necessary. Finally,
if bit 7 = 1 for the first, second, and third bytes is set, a final fouth
byte is read in which all 8 bits are included in determining the integer value.
(Hence, the total number of possible bits for a value is 32 - 3 = 29, the
three bits not used representing the "read next byte" flags.)
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
The value bits (7, 14, 21, or 29 bits in total, represented by an "x" above) are to
be interpreted, either in little or big endian order (depending on the synchronization/endian
byte value), as the final unsigned integer value.
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.
(If GPS PRN numbers of 33-37 are ever used, a different encoding will have to be implimented.)
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 & 0x03 (for up to and including 4 systems)
- satellite number = (byte & 0x1f) + 0x01
Currently, for the satellite system:
- 0x00 = NAVSTAR GPS system
- 0x01 = GLONASS system
- 0x02 = WAAS/EGNOS/MSAS geostationary SBAS
- other values reserved; including bit 7 which is reserved in case more than 4 systems
need to be defined in the future, whereupon satellite system = byte >> 5 & 0x07
For the satellite number:
- satellite number = PRN # if SV in the NAVSTAR GPS system
- satellite number = slot # if SV in the GLONASS system
- satellite number = PRN # - 119 if SV in WAAS/EGNOS/MSAS (i.e. PRN # - 120 == 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 (BINEX) and re-rounding
the value to the nearest 0.001 (RINEX).
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.262
So, 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 -> 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).
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, 23-Oct-2007 13:37:46 UTC
|