The NavFactory classes provide an interface for searching for navigation message data, including ephemeris, almanac, health ionospheric, ISC and time offset data, where
The simplest portion of this interface is defined in the NavLibrary class, which provides an interface for computing the satellite XVT at a given time. Refer to that class' documentation for a simple example of its use. The NavLibrary class also provides an interface for retrieving health status information and time offset information.
The NavLibrary class, which provides the highest-level interface, has four primary entry points for looking up navigation message data:
Regarding NavLibrary::getXvt() and antenna phase center (APC), one exception to this rule is when using SP3 files as input. The data in an SP3 file can be referenced to the center-of-mass, or to the antenna phase center. There is no programattic way to distinguish between the two, so it's entirely up to the user in this case to know what they're doing.
The table below describes what search parameters are expected to be specified vs. may be wildcards ("Any") in that situation. In each case, the use of wildcards is given as an option, i.e. specific values may still be specified if desired.
The following generalized use cases are defined: \dictionary \dicterm{Low-Precision} \dicdef{Only a rough estimate of the satellite position is needed. Typically used for applications where only azimuth and elevation measurements are needed to precision of maybe a 10th of a degree. Almanac or Ephemeris data may be used in such cases. Examples: visibility plots or any other plot against elevation and/or azimuth is used.} \dicterm{High-Precision} \dicdef{When a more precise satellite position is required. In this case you would use ephemeris data, but not almanac data. Examples: observed range deviation (ORD) analysis, inter-signal correction estimation.} \dicterm{Known-Source} \dicdef{This situation is typically when you're analyzing signal health and you need to know the exact signal a given navigation message came from. You might be looking at any given nav message type in this case, even almanac data.} \enddictionary
Parameter | Low-Precision | High-Precision | Known-Source |
---|---|---|---|
sat.sat.id | specified | specified | specified |
sat.sat.system | specified | specified | specified |
sat.xmitSat.id | wild | wild | specified |
sat.xmitSat.system | wild | wild | specified |
sat.system | specified | specified | specified |
sat.obs.type | wild | wild | wild |
sat.obs.band | wild | specified | specified |
sat.obs.code | wild | specified | specified |
sat.obs.xmitAnt | wild | specified | specified |
sat.obs.freqOffs | GLONASS | GLONASS | GLONASS |
sat.obs.mcode | wild | wild | wild |
sat.nav | wild | specified | specified |
In most cases, you'll want to use NavLibrary in conjunction with MultiFormatNavDataFactory to access navigation messages. This provides a relatively simple interface while simultaneously supporting multiple input formats, with the expansion of that set of supported input formats happening without the need for additional code changes.
The process for using NavLibrary in this fashion involves the following steps:
Here is an example code snippet of how one might use NavLibrary for a low-precision use case. The getXvt() call in this example allows derivation of XVT data from either an almanac or ephemeris message:
Here is a reduced example code snippet of how one might use NavLibrary for a high-precision use case. In this example, the getXvt method that enforces the use of either almanac or ephemeris is used, and is forced to use only ephemeris data.
Here is a reduced example code snippet of how one might use NavLibrary for a known-source use case. This is much the same as the high-precision case, but with more details specified for matching.
This code snippet shows how one might take the results of a class derived from PNBNavDataFactory and immediately process the resulting decoded messages, looking at individual data fields. Something like this would be used if there's no intent to store the data internally for searching.
Some practical examples may be found in gnsstk (library code). These are:
Source file | Use case |
---|---|
EphemerisRange.cpp | Get Xvt+IODC+health |
BCIonoCorrector.cpp | Look up ionospheric corrections |
BCISCorrector.cpp | Look up inter-signal corrections |
More complete practical examples for NavLibrary and related classes can be found in the gnsstk-apps repository. Those are:
Source file | Use case |
---|---|
timeconvert.cpp | Look up TimeOffsetData and change time systems. |
navdump.cpp | Dump data, look up arbitrary data types, compute |
Xvt, load different data types from different | |
files. | |
WhereSat.cpp | Print Xvt of all known satellites in a time range |
(If you see ^ rendered in the table above, try a newer version of Doxygen)
Practical examples using Python are somewhat scarce, but what there is can be found in swig/tests, e.g. test_NavLibrary.py.
The NavLibrary entry points have a common set of parameters that are specified when searching for data. With the exception of the find() method, defaults are used for these parameters that were deemed the most likely values across typical use cases and these are typically safe values to use in a given situation. Changing from the defaults is only likely in the event of implementing an atypical use case.
The common parameters are: \dictionary \dicterm{sat/nmid} \dicdef{The full signal/message specification to search for.} \dicterm{when} \dicdef{The time you're interested in getting the health, time offset, Xvt, etc.} \dicterm{xmitHealth} \dicdef{Allows you to specify the desired health state of the satellite that transmitted a given nav message at the time of interest. DEFAULT=Any} \dicterm{valid} \dicdef{Allows you to specify whether you want navigation messages that passed or failed validity checks. DEFAULT=ValidOnly} \dicterm{order} \dicdef{Allows you to specify whether you want the data that would have appeared in a near-real-time situation or if you want the data with the closest time stamp. DEFAULT=User} \enddictionary
Most of these parameters have a wildcard (aka "don't care", aka "Any") value, meaning that any value for that parameter will match. The when and order parameters are exceptions to this - they must always be specified as a fixed, single value.
The sat and nmid parameters specify a great deal of detail about the data you're interested in, and this is where most of the use-case-specific tweaking will be done.
The sat parameter is a NavSatelliteID object, while nmid is a NavMessageID object. NavMessageID inherits from NavSatelliteID (click for class/inheritance diagram), and adds the messageType parameter.
The classes contain the following data:
\dictionary \dicterm{messageType} \dicdef{(nmid/NavMessageID only) Specifies what type of navigation message is being stored or searched for, e.g. NavMessageType::Almanac, NavMessageType::Ephemeris, etc.} \dicterm{sat} \dicdef{The subject satellite ID (SatID). This is the satellite to which the data applies. This may be different from xmitSat, and typically is in the case of almanac data. This is the satellite whose health or position you want.} \dicterm{xmitSat} \dicdef{The ID of the satellite that transmitted the navigation message. In most cases is the same as sat, but may be different for almanac data. Can be a wildcard value if, for example, you want almanac data but don't care what the transmitting satellite was. Ephemerides will have the same sat and xmitSat values and can be specified this way when searching.} \dicterm{system} \dicdef{This specifies the SatelliteSystem whose data is identified or being searched for. This is distinct from the system in sat and xmitSat for two reasons, one is that some systems have been known to broadcast data about other systems (QZSS test broadcasting GPS navigation messages for example). Another is that the NavSignalID class that contains the information does not contain the satellite data, but is in some cases used independently of the satellite ID.} \dicterm{obs} \dicdef{This specifies the CarrierBand and TrackingCode and other relevant information describing a signal. These can be set to wildcard values as well when searching.} \dicdef{nav} \dicdef{This specifies the navigation message structure from which the data was derived, e.g. gnsstk::NavType::GPSLNAV. This too can be specified as a wildcard using gnsstk::NavType::Any.} \enddictionary
SatID data is used in two ways in the NavSatelliteID class. One is to identify the transmitting satellite, and the other is to identify the subject satellite. These are distinct for the case of almanac data, where each satellite in a given constellation broadcasts low precision orbital elements ("almanacs") for every satellite in the constellation.
In most situations, the transmit satellite may be set to wildcard values in the search parameters.
The satellite is identified using a combination of the satellite system and the system-specific identifier (e.g. PRN for GPS).
A SatID may be made into a wildcard by one of two ways, either by calling the SatID::makeWild() method, or by setting SatID::wildId and/or SatID::wildSys individually (the former is recommended if the SatID is meant to match anything, as it should be kept up-to-date with any internal data changes).
The ObsID class identifies an observation of a signal from a satellite. This includes the observation type (in this case, always navigation messages), the carrier band, tracking code, transmitting antenna, and, in the case of GLONASS, the frequency offset for the FDMA constellation. Depending on your use case (see Use Cases above), you may wish to specify this data or not.
Bit fields for M-Code data are also present in the ObsID class for matching, but use cases for anything but wildcard matches will be extremely rare.
The when parameter specifies a time of interest. There aren't too many restrictions on this, except that the time system should match the satellite system of interest (or time system, when getting time offset information), or otherwise be set to TimeSystem::Any.
The xmitHealth parameter allows you to specify whether you want your data to come from a satellite that is healthy, or unhealthy, or if you don't care.
If a default value is set in the method prototype at all, the default is SVHealth::Any, which means you don't care whether the transmitting satellite is healthy or not.
If you only want data transmitted by healthy satellites, then specify SVHealth::Healthy.
If for some reason you only want data from unhealthy satellites, then specify SVHealth::Unhealthy.
One last option for health is SVHealth::Degraded, however this is a very limited use case as currently it is only utilized by the Galileo implementation.
The valid parameter allows you to specify whether or not you want to do validity checks on the navigation data before using it. When methods have a default for this parameter, it is to perform validity checks.
The validity checks are performed was the data is added to the NavDataFactory. The validity checks are all specific to each navigation message, and usually consists of range checks on decoded values.
Other values are NavValidityType::InvalidOnly, which runs validity checks and only accepts data that fails. Finally is the ubiquitous NavValidityType::Any value which skips the validity checks altogether and doesn't reject any data.
The order parameter has two possible values, NavSearchOrder::User, which most closely resembles the behavior a user would see when using a receiver in near real-time, and NavSearchOrder::Nearest which looks for data with the timestamp closest to when, forward or backward in time.
Most use cases will want to use NavSearchOrder::User, and this is the default when one is specified. NavSearchOrder::Nearest is only used in vary specific cases that you probably already know if you're going to use it at all.
The NavFactory classes are designed with several goals in mind (in no particular order):
The end result is a design that includes the following:
The NavFactory classes are designed to be extensible, as noted above. This is done using two classes: MultiFormatNavDataFactory and PNBMultiGNSSNavDataFactory.
The MultiFormatNavDataFactory class is a child of the NavDataFactoryWithStoreFile class that keeps track of other NavDataFactoryWithStoreFile classes. It works by "farming out" requests to factories that are capable of handling them. The determination of whether a factory is capable of handling a given request is used by mapping each of the signals supported by the factories to the factory itself, therefore when a find request is made to MultiFormatNavDataFactory, it looks up the requested signal in the map of factories and tries matching factories until one succeeds (giving up if none succeed).
The MultiFormatNavDataFactory may be added as a single factory to the NavLibrary.
The reason for having this particular factory rather than adding each individual NavDataFactory to a NavLibrary (which is also still possible) is where the extensibility comes in. The MultiFormatNavDataFactory::factories data member is declared static and is initialized at run time, which not only allows for dynamic configuration of factory support, but also allows for other libraries to add support for factories that do not exist in the gnsstk.
As an example, support for RINEX NAV and SP3 is implemented in the core gnsstk, but support for Yuma and SEM format files is only present in the ext code. While in this particular case, using compiler directives would have worked to decide whether to add support for Yuma and SEM, that wouldn't have worked for external formats. You may have proprietary formats you wish to support, file or real-time. These can be added as described in Adding Custom NavData Factories.
The end result of all of this is that if you have a tool that is written to use NavLibrary with MultiFormatNavDataFactory, as long as you're not digging deep into the detailed specifics of the factory or data classes, all that is required to add support for additional formats is to link the library implementing the format to that executable.
The PNBMultiGNSSNavDataFactory class design is much like the MultiFormatNavDataFactory class. It also has a static data member PNBMultiGNSSNavDataFactory::factories where classes derived from PNBNavDataFactory can be added to support the decoding of additional signals. This is also initialized by libraries at run-time.
There is no NavLibrary equivalent for PNBNavDataFactory. Instead, a class derived from NavDataFactory that is expected to process the raw navigation messages from multiple systems would use an instance of this class to decode the raw navigation messages in the form of PackedNavBits. Data goes through the translation process using PNBNavDataFactory::addData(), the results of which can be stored or used as appropriate.
There are currently no factories in ext that are being added this way, however instructions for doing so can be found in Adding Custom PNBNavData Factories.
If you wish to add support for additional file formats to MultiFormatNavDataFactory, you will need to do the following:
Adding support for additional nav message data decoders can be added to PNBMultiGNSSNavDataFactory. You will need to do the following:
There are no examples of this outside the gnsstk core, however one may look at core/lib/NewNav/NavStatic.cpp to see how this is done for the core PNBNavDataFactory classes. There should be little difference for outside code.