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: GAGE BINEX contact
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.)
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) + 1 to +2^(N-1) - 1
and -2^(N-1) is reserved to indicate an invalid or unknown value;
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 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 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:
There are then four possible type of byte sequences possible:
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:
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:
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:
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":
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:
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:
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:
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.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 -> 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: 2023-05-12 13:23:22 America/Denver