Version 1.0.1. → Change List | helmut@stettmaier.de |
A System of data formats and vocabularies is presented. The definitions are used to fully describe, formally and semantically, a data item received from the telemetry data receiving unit in a RC transmitter device.
Following these definitions shall make it easier to process and render these data and it shall support portability of software and usefulness of rendering devices.
Currently this article is a request for comments.
Copyright © 2018 Helmut Stettmaier. All rights reserved.
This document may freely be copied or published but it must not be modified in any way. Requests for modifications must be sent to the author or a person authorized by the author for review and maintenance.
1 Motivation
2 Overview
3 Data Formats
3.1 Internal Data Formats
3.2 External Data Format
4 Data Semantics (Vocabularies)
4.1 Numerical Properties
4.2 Physical Meaning
5 Glossary
6 Few Detailed Considerations
Change List
Telemetry data are acquired in the aeromodel by sensor devices - there are very different kinds of such sensor devices and data acquisition system architectures. The data are sent “down” to the RC transmitter (acting as a receiver in this case). The protocols fit somehow into the WiFi framework, WiFi hardware is employed, but the used systems differ significantly and are not compatible.
Many or most RC transmitter devices allow the down coming telemetry data stream to be listened to by other devices as long as the data stream protocol and the data formats are understood. Not all manufacturers publish their “telemetry protocol” and the data formats, but perhaps some see, with some eye twinkle, “hacking” these informations as a qualification for joining the game.
Currently computers, which extensively (as the reason for existence) process and render telemetry data do not belong to the RC transmitter but work externally and it would be a really good idea when such “Render Engines” can be connected to different RC brands' transmitters and differ only in their drivers for the RC equipment but are equivalent otherwise. It, of course, should be possible to use data processing or rendering routines without changes.
Render Engines will offer fields for experiments and experimenters! Data processing or rendering routines may be shared as libraries or as source programs and working with standard data formats with unified semantics is a prerequisite to achieve this.
Telemetry data may be logged, post processed and compared to others. In the future such data may be exchanged “live” over a local network. All this is easier to perform when standard data formats are used.
The proposed Standard for data description consists of several parts:
The intended usage is as follows:
Data, as acquired by sensor devices, are subjects to limitations: The most common limitation is the resolution, e.g. many aeromodelers' altimeters yield the height with a resolution of 1m.
The data are transferred “down” to the RC transmitter and during transmission additional restrictions may come into effect, mainly because of the transmission formats dictated by low bandwidth.
When the data are read out of the radio module of the RC "transmitter" device into the Render Engine the input driver in the Render Engine “must know” about the type of the data and the limitations of the sensor device and the transmission channel; it must choose the corresponding type code and the numerical properties for the received data item. Finding out the semantic meaning and the numerical properties depends on the transmission protocol and data format: its position in a large block (Graupner's HoTT®) or on several additional information per (shorter) block (Multiplex' MLink® / MSB®) and must be hard coded and/or controlled by user defined operational parameters.
An Example: The input driver in my Render Engine reads MLink / MSB data. An MSB-block contains
a number, an alarm flag, a data type code and a channel number. The user configures the sensor device
on which channel the value is to be sent (this controls the standard rendering); in this example
I set channel=2. The type code used by MSB sensor devices for “height / short
distance” is 8. So I can state that a value of type 8 and transmitted over channel 2 is
the height above ground level (AGL) in [m]. The Render Engine reads an operational parameter
how “to translate a data item <channel 2 & Type 8> into <Altitude relative /
float / resolution 1m / range -16347..+16347>” - see Numerical Properties.
So, when the data has passed the input driver, is well formatted as vehicle's height in [m] in a
standardized numerical format.
Other information for the telemetry data item may be generated by the driver, most prominently the time-stamp.
Processing routines may generate new data out of more received data, e.g. TEK calculation: The CAS (calibrated air speed) may be used to compensate the climb speed by eliminating “stick thermal”. In this case two data items (uncalibrated climb speed and CAS) are used to create another item (TEK calibrated climb speed). Such computations need not only the “correct formula” but also thorough checks for overflows or other numerical traps and thoroughly evaluating the numerical properties of each input item and also formulating the resulting numerical properties of the result.
Telemetry data are processed internally in the Render Engine, processing routines may be exchanged as sources or as libraries - this makes it necessary to use standard data structures. I define such structures for C and C++, other programming languages will follow.
Telemetry data are stored permanently (logged) and read by “other” programs, or, in the future, even exchanged when RC transmitters form ad hoc networks. Thus an external data format for storing and transmitting these data is defined.
These definitions do not contain specifications for semantics (except for the time-stamp), this is described later in Data Semantics.
The Render Engine's input driver yields telemetry data items one by one in real time as they come in. Input data formats may deliver more than one data items as they may be clustered in one transmission block. Therefore it is possible (even usual) that the input driver delivers few data items together. Optionally the driver could deliver these data items “together” in an array or a similar method, but the application reading these items SHOULD NOT rely on this, as this might be a handicap for designing portable applications (portability regarding different RC systems). In contrary, the application SHOULD store received data items in its own local storage and, when combining them, thoroughly check the time-stamps to see if the data items really are related.
An example: The HoTT system may transmit true climb speed and speed (IAS) together in one transmission block and when the one item is received correctly, the other will also be correct. For the MLink / MSB system this is not necessarily the case as the true climb speed and speed (IAS) are transmitted in different blocks, possibly with different frequencies (for example height prioritized about 10 times per second, speed about 2 times per second), and one of them may be lost. This might affect TEK calculation.
These formats are defined using programming languages. This may be affected by the endianess of the computer in use, therefore block graphics are not used. Applications SHALL NOT depend on specific orders of bytes in words or bits in bytes other than explicitly specified here.
A telemetry data item consist of:
... for a telemetry data item is in C:
typedef struct {
TDISpec_t s;
uValue_T v;
uint32_t timestamp;
} TDItem_t;
void serialize(TDItem_t &this, void *(uint8_t b)sendByte());
void deserialize(TDItem_t &this, uint8_t *()receiveByte());
The full C++ class declaration for a telemetry data item is:
class CTDItem {
protected:
TDISpec_t s;
uValue_T v;
uint32_t timestamp;
public:
CTDItem();
void clear() { s.w= v.uiValue= timestamp= 0; };
uint16_t getTDSemantic();
void setTCSemantic(uint16_t semcode);
int8_t getNumCode();
int8_t getNumSubCode();
void setTDNum(uint8_t numcode);
uint8_t getTDFlags();
void setTDFlags(uint8_t statcode);
int isTDItemDefined();
int isTDItemValueDefined();
int isTDItemTimestampDefined();
int32_t getiValue();
void setiValue(int32_t val, uint8_t numsubcode= TDNUM_UNDEF);
uint32_t getuiValue();
void setuiValue(uint32_t val, uint8_t numsubcode= TDNUM_UNDEF);
float getfValue();
void setfValue(float val, uint8_t numsubcode= TDNUM_UNDEF);
q1516_t getq1516Value();
void setq1516Value(q1516_t val, uint8_t numsubcode= TDNUM_UNDEF);
qwgs84_t getqwgs84Value();
void setqwgs84Value(qwgs84_t val, uint8_t numsubcode= TDNUM_UNDEF);
uint32_t getTimestamp();
void setTimestamp(uint32_t ts);
void serialize(void *(uint8_t b)sendByte());
void deserialize(uint8_t *()receiveByte());
}
Normally the getter and setter functions are defined in the header file as inlines, but this is out of scope for this paper.
The time-stamp has a resolution of 1 ms. The time corresponding to the value 0 is less precise defined: Usually you may use the power on time. This may cause minor challenges when logs are to be evaluated, or it may cause more important questions when several Render Engines are connected via a network, as they are switched on at different times. This question is not treated now in detail as such networks are not projected; such a protocol will include CTDItem instances with only a time-stamp defined for synchronization.
It is to be expected that, at least in “smaller” implementations of Render Engines, those data structures are not created dynamically but are stored in static instances or in queues and are reused when new data come in, therefore the extra function clear() is foreseen.
None of these functions is thread safe. At least in “smaller” implementations of Render Engines concurrency problems may be avoided very simply and in “other” implementations the CTDItems transporting queues are better places to handle concurrency problems.
The sub structure for the semantical specification is in C:
typedef union {
uint32_t w; ///< guarantees atomic access and word alignment
struct {
uint8_t flags; ///< see enum eTDIflagcodes
uint8_t num; ///< see TDNUM_...
uint16_t sem; ///< see TDEL_SUPPLY etc.
} b;
} TDISpec_t;
The meanings of the flags are defined in an enumeration:
enum eTDIflagcodes {
TDIstatUndef= 0, ///< The sensor device signals "undefined value".
TDIstatNormal= 1, ///< Normal state.
TDIstatWarning= 2, ///< Sensor device signals "Warning" for the value.
TDIstatAlarm= 3, ///< Sensor device signals "Alarm" for the value.
TDIstatMask= 3, ///< Masks all stat bits
TDIvaluedefined= 4, ///< Set when the input driver has set the value
TDItstampdefined=8, ///< Set when the time-stamp is defined
};
There are left some bits for future extensions. Notes:
CTDItem::s.b.flags==0
means this item is to be ignored.... can be of one of several types and here is a definition of a corresponding union type:
typedef union {
int32_t iValue;
uint32_t uiValue;
float fValue;
q1516_t q1516Value;
qwgs84_t qCoordinateValue;
} uValue_T;
It depends on the numerical properties of the data item which alternative of this union is chosen to store the value of the item. There is no “default” defined. Any telemetry data item producing code (input driver or application code) MUST use the alternative that is named in the numerical properties code.
The external data format is used when telemetry data items are stored (logged) or, in the future, are sent to or received from other devices in a local network.
The format is related to RFC 4506 which describes data formats for transmission in the Internet and a specification language, “XDR”. Of course RFC 4506 cannot be applied 1:1 as several data types are not specified, but these main features do apply:
The format is simple:
An example (for detailed codes see below): A CTDItem instance with the listed contents is serialized into the given byte stream:
e7 42 43 0c 00 21 33 34 00 01 11 11
.
There is no escape symbol or synchronization mechanism foreseen, the data link layer must take care of proper framing etc.
Vocabularies and dictionaries are used to specify semantics and number formats. There is a “mother list” of vocables and the corresponding meaning. Other formats can be derived from this list:
Some grouping and refinement is used to improve usability.
Numerical properties of a data item consist of
It's hereby promised that code 0 for the range or resolution always means “undefined”: No information regarding the range or the resolution is available but the value is valid in the sense, that it really was acquired regularly.
The following data types and range or resolution codes are foreseen:
32-bit integers with two's complement are used, the “natural” range goes from -2147483648 to 2147483647. The resolution of integer values is (naturally) 1.
The range of values for signed integer numbers may be limited, up to 15 codes for explicitly defined ranges are provided:
symbol | TDNUM_UNDEF | TDNUM_SIGN | TDNUM_1 | ... | TDNUM_FULLRANGE |
code | 0 | 2 | 1 | ... | 15 |
range | undefined | 0 | -9..+9 | ... | full range |
(to be revised)
The type code for signed integers is: TDNUM_INT32= 0x10
and it is ORed with
the range code. Examples:
TDNUM_INT32 | TDNUM_1
denotes a signed integer that may have
a value ≥-9 and ≤+9. TDNUM_INT32 | TDNUM_SIGN
denotes a signed integer with no digits. It may
be used to represent flags to distinguish between “left” and “right” or
“lower” and “not lower”.
32-bit integers are used, the “natural” range goes from 0 to 4294967295. The resolution of integer values is (naturally) 1.
The range of values for signed integer numbers may be limited, up to 15 codes for explicitly defined ranges are provided:
symbol | TDNUM_UNDEF | TDNUM_BOOL | TDNUM_RSSI | TDNUM_1 |
code | 0 | 2 | 3 | 1 |
range | undefined | 0..1 | 0..5 | 0..9 |
symbol | ... | TDNUM_FULLRANGE |
code | ... | 15 |
range | ... | full range |
(to be revised)
The type code for unsigned integers is TDNUM_UINT32= 0x20
and it is ORed with
the range code. Example: b.num= TDNUM_UINT32 | TDNUM_1
denotes an unsigned
integer that may have a value up to 10.
Usage of this type depends on the MCU on which the Render Engine is running.
When a floating point unit (FPU) is available, as is the case with most ARM Cortex M4 MCUs, using float is the best choice in many cases. On other MCUs float numbers must be processed using a float library and this might be very slow.
When telemetry data are received from the RC transmitter the user dictates what is translated to what and he or she may avoid floats, but when telemetry data items are read from a log or are received via a network, floating point data types can possibly not be avoided and must be converted when no FPU is available.
IEEE-754 defines special codes for +infinity, -infinity and for “not a number” - these codes
SHALL be used appropriately and even values, which are received from a network, may contain these codes.
C / C++ allows tests using isnan() and isinf(), but distinction between +inf and -inf must be done
extra: if (value<0 && isinf(value)) ...
Floating point numbers are used to represent physical values that are measured with limited resolution (precision, measurement errors etc. are NOT discussed here). Sensor devices are specified to deliver such values with step widths of “0.1 V”, “mA” or “100 m” for example. The scaling factors are already counted for during translation: When a sensor device delivers 24 meaning “2.4 V”, the factor 10 is already divided (to get 2.4 out of 24), but further processing might be influenced by the step widths.
There are codes provided for the following resolutions:
symbol | TDNUM_UNDEF | TDNUM_1 | TDNUM_10 | TDNUM_100 |
code | 0 | 1 | 2 | 3 |
resolution | undefined | 1 | 10 | 100 |
symbol | TDNUM_1000 | TDNUM_01 | TDNUM_001 | TDNUM_0001 |
code | 4 | 9 | 10 | 11 |
resolution | 1E3 | 0.1 | 0.01 | 1E-3 |
(To be revised!)
The resolutions apply to the physical unit that is defined in the physical meaning of the item.
The type code for float numbers is TDNUM_FLOAT32= 0x30
and it is ORed with the
resolution code
Examples:
Voltages are measured in V, the “correct” value of 3.5V is stored in a float number +3.5.
When the sensor device can only deliver values of multiples of 0.1 V, the resolution code
TDNUM_01
is to be used.
And a Shepard Tone rendering of a high definition height cannot be done using a telemetry height data
item that has a resolution of 1 m (code TDNUM_1
).
This is a fixed point rational number format. It is 32 bits long, the 16 less significant bits are used as fractional part, the upper 16 bits are used as integral part, including the sign bit. q15.16 numbers are, in fact, signed integers and, as a convention, the intended value is computed by dividing the integer value by 65536. The numerical range of such numbers goes from about -32768.999985 to +32768.999985 and the ε ≈ 0.000015. The hexadecimal word 0x00010000 represents the number 1.
Trivial looking numbers like 0.1 cannot be represented exactly, as is also the case for float numbers, and must be approximated. An example is: the q15.16 value of 0.1 is approximated by 0x0000199a, what represents the q15.16 value of 0.100006 .
The q15.16 is format is, a bit surprisingly, suitable for most telemetry data in the field of aeromodeling and arithmetic operations can be easily performed on MCUs without floating point unit, but the implementation of q15.16-arithmetic is beyond the scope of this paper.
There are codes provided for the following resolutions:
symbol | TDNUM_UNDEF | TDNUM_1 | TDNUM_10 | TDNUM_100 |
code | 0 | 1 | 2 | 3 |
resolution | undefined | 1 | 10 | 100 |
symbol | TDNUM_1000 | TDNUM_01 | TDNUM_001 | TDNUM_0001 |
code | 4 | 9 | 10 | 11 |
resolution | 1E3 | 0.1 | 0.01 | 1E-3 |
(To be revised!)
The type code for q15.16 numbers is TDNUM_Q1516= 0x40
and it is ORed with the
resolution code.
An example is: TDNUM_Q1516 | TDNUM_01
may be good for a
telemetry data item that contains a value from a voltage sensor that can measure in 0.1-Volt-steps
and stores the value as a q15.16 number.
This ugly data format is defined for WGS84 coordinates. The standard format for such coordinates is a rational number with an integral part for the degrees and a “continuous” fractional part. The traditional format using degrees, minutes and seconds (the seconds with a fractional part) is impractical, it may be used to find a position in a traditional map and SHOULD therefore only be used for rendering. Example: Standard format: +48.362295°, traditional format: 48°21'44.262"N.
This data format has a 9-bit signed integer part that can hold the numbers -256 to +255, good for the -180° to +180° range. The fractional part holds the part <1°, it has 23 bits, so the ε ≈ 0.00000012 what is viewed sufficient for all practical cases.
The type code for qwgs84_t numbers is TDNUM_QWGS84= 0x90
and it is ORed with an
sub-code for the type of the coordinate (longitude, latitude) and for the resolution delivered
by the GPS device:
symbol | TDNUM_LON_UNDEF | TDNUM_LON01 | TDNUM_LON05 | TDNUM_LON1 |
code | 0 | 1 | 2 | 3 |
data type | longitude | longitude | longitude | longitude |
resolution [m] | undefined | 0.1 | 0.5 | 1 |
symbol | TDNUM_LON5 | TDNUM_LAT_UNDEF | TDNUM_LAT01 | TDNUM_LAT05 |
code | 4 | 8 | 9 | 10 |
data type | longitude | latitude | latitude | latitude |
resolution [m] | 5 | undefined | 0.1 | 0.5 |
symbol | TDNUM_LAT1 | TDNUM_LAT5 |
code | 11 | 12 |
data type | latitude | latitude |
resolution [m] | 1 | 5 |
There are groups of items belonging together. Examples are:
TDEL_SUPPLY
, a collection of items belonging to the RC-supply of the model
airplane,TDEL_DRIVE
, a collection of items belonging to the (electric) drive system
of the model airplane. Many of the items of the TDEL_SUPPLY
group are also applicable
in the TDNAV_DRIVE
group (accumulator voltages for example).There can be defined up to 255 groups, the constant representing a group occupies the upper byte in
s.b.sem. Examples: TDEL_SUPPLY
has the code 0cf7 and TDNAV_DRIVE
has the
code 0cf6.
Items, members of groups, specify the details of what is being meant. Examples:
TDNAV_VEHICLE
“contains” (among others) the following items:
TD_HEIHGT_REL
(the height above some reference altitude, for aeromodelers almost
every time the ground elevation) that is acquired and transmitted by most altimeter sensor devices
during flight.TD_SPEED_CLIMB
and TD_SPEED_CLIMB_COMP
, the two flavors of climb,TD_SPEED_IAS
and all the other speed flavors up to TD_SPEED_GND
,TD_LATITUDE
and TD_LONGITUDE
.TDNAV_REFERENCE
“contains” (among others) the following items:
TD_ALTUTUDE_MSL
that might be acquired and transmitted by a sensor device during
setup and may be registered by the Render Engine for converting a CAS into a TAS.TD_LATITUDE
and TD_LONGITUDE
.Item codes occupy the lower byte of s.b.sem. Examples: TD_SPEED_CLIMB
has the
code 0x40; TD_TEMPERATURE
has the same code, but the ambiguity is resolved using
the group code, as any speed is never a member in the TDEL_SUPPLY
or
TDEL_DRIVE
etc. groups and any temperature is notmember in a TDNAV_... group.
Some item codes, where appropriate, leave 4 bits free for an index, to specify furtherly
what is meant.
Example: TDEL_SUPPLY | TD_VOLTAGE | 1
specifies the voltage of the
2nd cell (counted from 0 up) of the accumulator of the RC supply. If more accumulators are
in use, the cells SHALL be unique: Cells 0 and 1 for the first accumulator, 2 and 3 for
the second accumulator.
More Examples:
TDEL_SUPPLY | TD_VOLTAGE | 0
..
TDEL_SUPPLY | TD_VOLTAGE | 3
.TDEL_SUPPLY | TD_CURRENT | 0
and
TDEL_SUPPLY | TD_CURRENT | 1
.TDNAV_REFERENCE | TD_ALTUTUDE_MSL
at the beginning of the flight,TDNAV_VEHICLE | TD_HEIHGT_REL
as a streamTDNAV_VEHICLE | TD_SPEED_CLIMB
as a streamTDNAV_VEHICLE | TD_DYNAMIC_PRESSURE
as a stream; the Render Engine computes a
value of the
indicated airspeed of the TDNAV_VEHICLE | TD_DYNAMIC_PRESSURE
's value and stores it as an
TDNAV_VEHICLE | TD_SPEED_IAS
item. When no compensation of the errors inherent to the measurement device and caused by the flow is known, both errors are viewed to be “small”,
even negligible, the Render Engine makes a TDNAV_VEHICLE | TD_SPEED_CAS
of the
computed IAS value… In other cases, when calibration data are known, this conversion may be
useful.TD_SPEED-CAS
and TD_SPEED_CLIMB
the TEK compensated climb
rate TD_SPEED_CLIMB_COMP
may be calculated.Altitude vs. Height Altitude is used for distances over a “non
regional” reference, mostly the mean sea level (MSL); for flying in the upper airspace the altitude
refers to MSL, but a standard pressure is used such that these altitude numbers do not depend on the
wheather.
Height is used for distances over regional references, mostly the ground elevation of the
next air field - for aeromodeling the elevation (altitude MSL) of the point, where the equipment is
switched on, is used.
ε Finest resolution which is possible with a specific number format.
IAS Indicated Airspeed, "what is yielded by the instrument", without any error compensation.
CAS Calibrated Airspeed, Errors yielded by the instrument and errors caused by the flow field around the body are compensated. NOT compensated are errors introduced by the altitude and by the Mach number.
TEK German, abbreviation for “Total Energie Kompensation”.
The following details are not closely related to the data formats described above, but yield some explanations or shall complete the specifications with "best practice" recommendations. When SHALL etc. is used it is really meant as described in RFC2119 & RFC8174.
ε
This is the value of the smallest step that can be counted within a numerical data.
Example: The q15.16 value (decimal value) that is coded with the hexadecimal word 0x10000 is 1.0 and
the decimal value coded with 0x10001, the next possible value, is 1.000015259, the ε for q15.16-numbers
is 0.000015259. A (single) float number has an ε of 2^-24≈ 5,96E−8, indicating 7..8 valid decimal
digits.
IAS vs. CAS
Officially IAS means “what the instrument indicates” without any
compensation for (known or unknown) errors. This is not what is meant in common use of this abbreviation.
Instrument errors are thoroughly measured and canceled out during instrument calibration. Other errors
like air flow disturbances are also known and compensated… for aviation instruments. The result
is the “calibrated air speed”, CAS, but it is mostly called IAS. Most aeromodelers do not
care about these errors as it is not easy to measure them without reasonable equipment, and simply
set IAS≡CAS. Rendering engines, that are conform to this standard, MUST distinguish between IAS and CAS
as sometimes compensations are possible and this must not introduce uncertainties or confusion.
When the sensor device does compensate instrument and air flow errors by itself these speed data MUST
be interpreted as CAS already by the input driver. When the sensor device does not compensate these
errors and sends IAS data the rendering engine MUST do the translation of IAS data into CAS data,
even when this translation is trivial (just change the code from IAS to CAS, when appropriate).
Discussion of the qwgs84_t format
One degree (°) on a orthodrome (e.g. the equator) around the earth, viewed as a sphere, represents
a length of 4E4km/360°= 111.1… km/°. A number that can resolve 1 m must distinguish values with
a difference of 1/111111.1…= 0.000009 and therefore must have (log(1/9E6)≈−5,046)→5 decimal digits
for the fractional part (in addition to the 3 digits of the integer part). As the numbers are binary
numbers a similar calculation for binary digits yields log(1/4E7)/(log(2)≈−16,76, meaning that at
least 17 bits are needed for the fractional part (and another 9 bits for the integer part and
the sign).
q15.16 numbers can not store such numbers and (single) float numbers can just store such numbers
(squeezing the last bit), but there is absolutely no reserve and the 1m resolution cannot be surpassed.
But a 32-bit word is really long enough to store these specific numbers. So the 32-bit word is divided
into an integer and a fractional part such that the standard format of a coordinate can be stored,
converted (e.g. to double) and processed or rendered.
As decimal fractional parts cannot be represented exactly binary numbers containing the minimal number
of bits tend to introduce an effect which looks like “irregular aliasing” for decimal
representations. This can be damped by… using more bits. Additionally, future developments
will make affordable GPS/Galileo-devices possible which can resolve down to 10 cm and perhaps users will come
who need such positions, therefore any available bit should be used in the fractional part of
WGS84-numbers. This results in 9 bits for the integer part and the sign and 23 bits for the fractional
part.
Edit:
This data format is primarily used for transport and for the very first (simple) calculations, before
easier to be used formats become feasible. In most practical use cases 2 positions, acquired at different
locations, are to be subtracted to calculate azimuth and distance of the one location (aeromodel) to
the other (pilot). This subtraction suffers under the subtraction of 2 large but nearly equal numbers
which reduces relative precision dramatically - therefore as many bits in the fractional part as ever
possible are a good investment. 32 Bits - 9 bits for the integral part yield 23 bits for the fractional
part, 111111.11m/223≈0,013m. This is the resolution of N-S distances (for W-E
distances it is improved by cos(lat)). Let only be 3 bits "bad" and the resolution is only about
10cm. After this subtraction is is advised to convert the distances to more usable data formats, e.g
float or q1516.
Best practice dealing with numerical errors
Here is not the place to discuss try-catch-blocks.
Even smaller modern ARM cores (most Cortex-M4) have a floating point unit and using such numbers
reduces some problems, but exception handling and error reporting must be considered. Cortex M4 MCUs
provide only a single float FPU, double or extended operations are executed by library functions.
An IEEE 754 conformant FPU provides a standard error and exceptions scheme.
See GNU-clib chapter 20.5.4 to see what happens when a c floating point routine is called with illegal
arguments or cannot do what expected because of other reasons.
In general, when the (expensive) try-catch-functionality is used, it SHOULD always be used.
When a telemetry data item has an undefined value this is signaled in its flags byte s.b.flags.
In this case the value is really undefined, there is no statement what it contains, 0.0, NaN or anything
else. When a sensor device generates an "undefined" value the input driver MUST set the flag accordingly,
but writing an NaN into the value (if it is a float) is optional.
Vocabulary vs. Dictionary
Any attempt to specify semantics employs some vocabulary to say “This means that and this2 means
that2”. “This” and “this2” are words (vocables) with a distinct meaning and
“that” / “that2” is a formulation of the meaning. We have no other applicable
means for formulation of semantics than human speech. The programmer understands this explanation and the
application code is written to act accordingly.
Please forgive me when I am too …basic: Vocables (symbolic names) are ok for the human reader, the programmer, but they must be mapped to binary constants - this mapping is done via dictionaries:
RFC 4506,
“XDR: External Data Representation Standard” from May 2006 by M. Eisler (Ed.),
Network Appliance, Inc., and others
RFC 2119, RFC 8174 (Explaining MUST, MUST NOT, SHALL, ...)
GNU clib: 20.5.4 Error Reporting by Mathematical Functions
Version | When | description |
---|---|---|
1.0.0 | May, 31st, 2018 | Initial version |
1.0.1 | October, 3rd, 2018 | Additional remark in "Discussion of the qwgs84_t format" in Ch.6 |