schwehr / libais

C++ decoder for Automatic Identification System for tracking ships and decoding maritime information
Other
215 stars 94 forks source link

Handling of N/A values could be improved #227

Open andyvan-trabus opened 2 years ago

andyvan-trabus commented 2 years ago

The current processing of values that need to be scaled or offset to yield "useful" values introduces some hardships for code that's trying to use the returned values.

Example AIS 8:1:21 message

Air Temperature is documented in the standard (IMO SN.1-Circ.289 - Guidance on ASMS.pdf) as follows:

Dry bulb temperature in degrees Celsius (as per 2's complement), in 0.1 degree steps. -60.0 to +60.0 degrees -1,024 = data not available = default 601 - 1,023 (reserved for future use) -1,023 to -601 (reserved for future use)

The current code always divides the 11-bit value by 10.0, which results in a floating-point number. However, if the original value was one of the "special" values, such as -1,024, it will also be converted. So, the client code, when checking to see if the value is available, has to do a floating-point compare to -102.4 (actually "-102.4000015258789" in my testing).

This is not good.

An improvement would be the following:

andyvan-trabus commented 2 years ago

Okay, my suggested solution won't work, in that the values presented to a C++ client won't be correct. I didn't realize that this library was able to be used directly from C code, I thought it was only for use with Python.

Alternate suggestion: Add checking code for special values in the bit-extraction routines, and if the value is out of range (e.g. N/A value), then if it's a float, set it to a NAN value. If it's an int value, we have a bool that we set to indicate that it's valid/invalid.

Example for 8:367:24. Pressure field is defined as follows:

Air pressure, defined as pressure reduced to sea level, in 1 hPa increments. 0 = pressure <800 hPa; 1 - 401 = 800 – 1200 hPa; 402 = pressure of 1201 hPa or greater; 403 = data unavailable = default; 404-510 = reserved; 511 = not to be used.

If int value is in 0..402, add 799 to the value, resulting in a valid pressure, and set pressure_valid to true; else leave value alone (don't add 799) and set new instance member pressure_valid to false;

This allows C++ code to tell whether a value is valid or not (pressure_valid field), and if not they actually have the value available in case that's useful. The Python mapping code in ais_py.cpp would check the value, and if pressure_valid is false, it would set the pressure field to Py_None. Alternatively, you could duplicate the C++ functionality and add a pressure_valid field to the Python dictionary.