mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-07-06 19:54:20 +00:00
253 lines
20 KiB
Plaintext
253 lines
20 KiB
Plaintext
|
/*! \mainpage
|
||
|
|
||
|
\image html gnss-sdr_logo.png
|
||
|
|
||
|
Welcome to GNSS-SDR!
|
||
|
|
||
|
GNSS-SDR is an open-source GNSS software receiver freely available to the research community. This project provides a common framework for GNSS signal processing which can operate in a variety of computer platforms. This tool is intended to foster collaboration, increase awareness, and reduce development costs in the field of GNSS receiver design and customized use of GNSS signals.
|
||
|
|
||
|
For details about GNSS-SDR and using it, please see the <a
|
||
|
href="http://gnss-sdr.org" target="_blank"><b>main project page</b></a> or browse the code at the <a
|
||
|
href="http://sourceforge.net/p/gnss-sdr/code/311/tree/trunk/" target="_blank"><b>Sourceforge project page</b></a>. You could be also interested in
|
||
|
<a href="http://lists.sourceforge.net/lists/listinfo/gnss-sdr-developers" target="_blank"><b>subscribing to the mailing list</b></a>.
|
||
|
|
||
|
\section toc Contents
|
||
|
\li \ref overview
|
||
|
\li \ref build
|
||
|
\li \ref control_plane
|
||
|
\li \ref signal_processing
|
||
|
|
||
|
|
||
|
More details on GNSS-SDR signal processing blocks:
|
||
|
|
||
|
\li \ref signal_source
|
||
|
\li \ref signal_conditioner
|
||
|
\li \ref channel
|
||
|
\li \ref observables
|
||
|
\li \ref pvt
|
||
|
\li \ref output_filter
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
\section overview Overview
|
||
|
GNSS-SDR provides an interface to different suitable RF front-ends and implements all the receiver chain up to the navigation solution.
|
||
|
Its design allows any kind of customization, including interchangeability of signal sources, signal processing algorithms,
|
||
|
interoperability with other systems, output formats, and offers interfaces to all the intermediate signals, parameters and variables.
|
||
|
The goal is to write efficient and truly reusable code, easy to read and maintain, with fewer bugs, and producing highly optimized executables
|
||
|
in a variety of hardware platforms and operating systems. In that sense, the challenge consists of defining a gentle balance within level
|
||
|
of abstraction and performance. GNSS-SDR runs in a personal computer and provides interfaces through USB and Ethernet
|
||
|
buses to a variety of either commercially available or custom-made RF front-ends, adapting the processing algorithms to different sampling frequencies, intermediate
|
||
|
frequencies and sample resolutions. This makes possible rapid prototyping of specific receivers intended, for instance, to geodetic applications,
|
||
|
observation of the ionospheric impact on navigation signals, GNSS reflectometry, signal quality monitoring, or carrier-phase based navigation techniques.
|
||
|
|
||
|
\image html overview.png
|
||
|
|
||
|
\section build Building GNSS-SDR
|
||
|
|
||
|
See the <a href="http://gnss-sdr.org/documentation/building-guide" target="_blank">building guide</a> page for details about the project's
|
||
|
dependencies and build process.
|
||
|
|
||
|
\section control_plane Control plane
|
||
|
GNSS-SDR's main method initializes the logging library, processes the command line flags, if any, provided by the user and instantiates a ControlThread object.
|
||
|
Its constructor reads the configuration file, creates a control queue and creates a flowgraph according to the configuration. Then, the program's main method
|
||
|
calls the run() method of the instantiated object, an action that connects the flowgraph and starts running it. After that, and until a stop message is received,
|
||
|
it reads control messages sent by the receiver's modules through a safe-thread queue and processes them. Finally, when a stop message is received, the main
|
||
|
method executes the destructor of the ControlThread object, which deallocates memory, does other cleanup and exits the program.
|
||
|
|
||
|
The GNSSFlowgraph class is responsible for preparing the graph of blocks according to the configuration, running it, modifying it during run-time and stopping it.
|
||
|
Blocks are identified by its role. This class knows which roles it has to instantiate and how to connect them.
|
||
|
It relies on the configuration to get the correct instances of the roles it needs and then it applies the connections between GNU Radio blocks to make the
|
||
|
graph ready to be started. The complexity related to managing the blocks and the data stream is handled by GNU Radio's <tt>gr_top_block</tt> class. GNSSFlowgraph wraps
|
||
|
the <tt>gr_top_block</tt> instance so we can take advantage of the \ref gnss_block_factory, the configuration system and the processing blocks. This class is also responsible
|
||
|
for applying changes to the configuration of the flowgraph during run-time, dynamically reconfiguring channels: it selects the strategy for selecting satellites.
|
||
|
This can range from a sequential search over all the satellites' ID to smarter approaches that determine what are the satellites most likely in-view based on rough
|
||
|
estimations of the receiver position in order to avoid searching satellites in the other side of the Earth.
|
||
|
|
||
|
The Control Plane is in charge of creating a flowgraph according to the configuration and then managing the modules. Configuration allows users to define in an easy way their own
|
||
|
custom receiver by specifying the flowgraph (type of signal source, number of channels, algorithms to be used for each channel and each module, strategies for
|
||
|
satellite selection, type of output format, etc.). Since it is difficult to foresee what future module implementations will be needed in terms of configuration,
|
||
|
we used a very simple approach that can be extended without a major impact in the code. This can be achieved by simply mapping the names of the variables in the
|
||
|
modules with the names of the parameters in the configuration.
|
||
|
|
||
|
\subsection configuration Configuration
|
||
|
|
||
|
Properties are passed around within the program using the ConfigurationInterface class. There are two implementations of this interface: FileConfiguration and
|
||
|
InMemoryConfiguration. FileConfiguration reads the properties (pairs of property name and value) from a file and stores them internally. InMemoryConfiguration does
|
||
|
not read from a file; it remains empty after instantiation and property values and names are set using the set property method. FileConfiguration is intended to be
|
||
|
used in the actual GNSS-SDR application whereas InMemoryConfiguration is intended to be used in tests to avoid file-dependency in the file system. Classes that
|
||
|
need to read configuration parameters will receive instances of ConfigurationInterface from where they will fetch the values. For instance, parameters related
|
||
|
to SignalSource should look like this:
|
||
|
|
||
|
\code
|
||
|
SignalSource.parameter1=value1
|
||
|
SignalSource.parameter2=value2
|
||
|
\endcode
|
||
|
|
||
|
The name of these parameters can be anything but one reserved word: implementation. This parameter indicates in its value the name of the class that has to be instantiated
|
||
|
by the factory for that role. For instance, if we want to use the implementation Pass_Through for module SignalConditioner, the corresponding line in the
|
||
|
configuration file would be
|
||
|
|
||
|
\code
|
||
|
SignalConditioner.implementation=Pass_Through
|
||
|
\endcode
|
||
|
|
||
|
Since the configuration is just a set of property names and values without any meaning or syntax, the system is very versatile and easily extendable. Adding new
|
||
|
properties to the system only implies modifications in the classes that will make use of these properties. In addition, the configuration files are not checked
|
||
|
against any strict syntax so it is always in a correct status (as long as it contains pairs of property names and values in <a href="http://en.wikipedia.org/wiki/INI_file" target="_blank">INI format</a>).
|
||
|
|
||
|
\subsection gnss_block_factory GNSS block factory
|
||
|
Hence, the application defines a simple accessor class to fetch the configuration pairs of values and passes them to a factory class called GNSSBlockFactory.
|
||
|
This factory decides, according to the configuration, which class needs to be instantiated and which parameters should be passed to the constructor. Hence, the factory
|
||
|
encapsulates the complexity of blocks' instantiation. With that approach, adding a new block that requires new parameters will be as simple as adding the block
|
||
|
class and modifying the factory to be able to instantiate it. This loose coupling between the blocks' implementations and the syntax of the configuration
|
||
|
enables extending the application capacities in a high degree. It also allows to produce fully customized receivers, for instance a testbed for acquisition
|
||
|
algorithms, and to place observers at any point of the receiver chain.
|
||
|
|
||
|
|
||
|
|
||
|
\section signal_processing Signal Processing plane
|
||
|
|
||
|
GNU Radio's class <tt>gr_basic_block</tt> is the abstract base class for all signal processing blocks, a bare abstraction of an entity that has a name and a set of
|
||
|
inputs and outputs. It is never instantiated directly; rather, this is the abstract parent class of both <tt>gr_hier_block2</tt>, which is a recursive container that
|
||
|
adds or removes processing or hierarchical blocks to the internal graph, and <tt>gr_block</tt>, which is the abstract base class for all the processing blocks.
|
||
|
|
||
|
|
||
|
\image html ClassHierarchy.png
|
||
|
|
||
|
A signal processing flow is constructed by creating a tree of hierarchical blocks, which at any level may also contain terminal nodes that actually implement signal
|
||
|
processing functions.
|
||
|
|
||
|
Class <tt>gr_top_block</tt> is the top-level hierarchical block representing a flowgraph. It defines GNU Radio runtime functions used during the execution of the
|
||
|
program: run(), start(), stop(), wait(), etc. A a subclass called GNSSBlockInterface is the common interface for all the GNSS-SDR modules. It defines pure virtual
|
||
|
methods, that are required to be implemented by a derived class.
|
||
|
|
||
|
Subclassing GNSSBlockInterface, we defined interfaces for the GNSS receiver blocks depicted in the figure above. This hierarchy provides the definition of different
|
||
|
algorithms and different implementations, which will be instantiated according to the configuration. This strategy allows
|
||
|
multiple implementations sharing a common interface, achieving the objective of decoupling interfaces from implementations: it defines a family of algorithms, encapsulates each one,
|
||
|
and makes them interchangeable. Hence, we let the algorithm vary independently from the program that uses it.
|
||
|
|
||
|
\subsection signal_source Signal Source
|
||
|
|
||
|
The input of a software receiver are the raw bits that come out from the front-end's analog-to-digital converter (ADC).
|
||
|
Those bits can be read from a file stored in the hard disk or directly in real-time from a hardware device through USB or Ethernet buses.
|
||
|
|
||
|
The Signal Source module is in charge of implementing the hardware driver, that is, the portion of the code that communicates with the RF front-end and receives
|
||
|
the samples coming from the ADC. This communication is usually performed through USB or Ethernet buses. Since real-time processing requires a highly optimized
|
||
|
implementation of the whole receiver, this module also allows to read samples from a file stored in a hard disk, and thus processing without time constraints.
|
||
|
Relevant parameters of those samples are the intermediate frequency (or baseband I&Q components), the sampling rate and number of bits per sample, that must be
|
||
|
specified by the user in the configuration file.
|
||
|
|
||
|
This module also performs bit-depth adaptation, since most of the existing RF front-ends provide samples quantized with 2 or 3 bits, while operations inside
|
||
|
the processor are performed on 32- or 64-bit words, depending on its architecture. Although there are implementations of the most intensive computational
|
||
|
processes (mainly correlation) that take advantage of specific data types and architectures for the sake of
|
||
|
efficiency, the approach is processor-specific and hardly portable. We suggest to keep signal samples in standard data types and letting the compiler
|
||
|
select the best library version (implemented using SIMD or any other processor-specific technology) of the required routines for a given processor.
|
||
|
|
||
|
Example: FileSignalSource
|
||
|
|
||
|
The user can configure the receiver for reading from a file, setting in the configuration file the data file location, sample format,
|
||
|
and the sampling frequency and intermediate frequency at what the signal was originally captured.
|
||
|
|
||
|
\code
|
||
|
;######### SIGNAL_SOURCE CONFIG ############
|
||
|
SignalSource.implementation=File_Signal_Source
|
||
|
SignalSource.filename=/home/user/gnss-sdr/data/my_capture.dat
|
||
|
SignalSource.item_type=gr_complex
|
||
|
SignalSource.sampling_frequency=4000000
|
||
|
SignalSource.freq=1575420000
|
||
|
\endcode
|
||
|
|
||
|
Example: UhdSignalSource.
|
||
|
|
||
|
\subsection signal_conditioner Signal Conditioner
|
||
|
The signal conditioner is in charge of resampling the signal and delivering a reference sample rate to the downstream processing blocks, acting as
|
||
|
a facade between the signal source and the synchronization channels, providing a simplified interface to the input signal.
|
||
|
In case of multiband front-ends, this module would be in charge of providing a separated data stream for each band.
|
||
|
|
||
|
|
||
|
\subsection channel Channel
|
||
|
A channel encapsulates all signal processing devoted to a single satellite. Thus, it is a large composite object which encapsulates the \ref acquisition,
|
||
|
\ref tracking and \ref decoding modules. As a composite object, it can be treated as a single entity, meaning that it can be easily replicated. Since the number of
|
||
|
channels is selectable by the user in the configuration file, this approach helps improving the scalability and maintainability of the receiver.
|
||
|
|
||
|
This module is also in charge of managing the interplay between acquisition and tracking. Acquisition can be initialized in several ways, depending on
|
||
|
the prior information available (called cold start when the receiver has no information about its position nor the satellites almanac; warm start when
|
||
|
a rough location and the approximate time of day are available, and the receiver has a recently recorded almanac broadcast; or hot start when the receiver
|
||
|
was tracking a satellite and the signal line of sight broke for a short period of time, but the ephemeris and almanac data is still valid, or this information
|
||
|
is provided by other means), and an acquisition process can finish deciding that the satellite is not present, that longer integration is needed in order to
|
||
|
confirm the presence of the satellite, or declaring the satellite present. In the latter case, acquisition process should stop and trigger the tracking module
|
||
|
with coarse estimations of the synchronization parameters. The mathematical abstraction used to design this logic is known as finite state machine (FSM), that is
|
||
|
a behavior model composed of a finite number of states, transitions between those states, and actions. For the implementation, we used the
|
||
|
<a href="http://www.boost.org/libs/statechart/doc/tutorial.html" target="_blank">Boost.Statechart library</a>,
|
||
|
which provides desirable features such as support for asynchronous state machines, multi-threading, type-safety, error handling and compile-time validation.
|
||
|
|
||
|
The abstract class ChannelInterface represents an interface to a channel GNSS block.
|
||
|
|
||
|
\subsubsection acquisition Acquisition
|
||
|
The first task of a GNSS receiver is to detect the presence or absence of in-view satellites. This is done by the acquisition system process, which also provides a coarse estimation of two signal parameters: the frequency shift
|
||
|
with respect to the nominal IF frequency, and a delay term which allows the receiver to create a local code aligned with the incoming code.
|
||
|
AcquisitionInterface is the common interface for all the acquisition algorithms and their corresponding implementations. Algorithms' interface, that may vary
|
||
|
depending on the use of information external to the receiver, such as in Assisted GNSS, is defined in classes referred to as <i>adapters</i>.
|
||
|
These adapters wrap the GNU Radio blocks interface into a compatible interface expected by AcquisitionInterface. This allows the use of existing GNU Radio blocks
|
||
|
derived from <tt>gr_block</tt>, and ensures that newly developed implementations will also be reusable in other GNU Radio-based applications.
|
||
|
Moreover, it adds still another layer of abstraction, since each given acquisition algorithm can have different implementations (for instance using
|
||
|
different numerical libraries). In such a way, implementations can be continuously improved without having any impact neither on the algorithm interface nor the general acquisition interface.
|
||
|
|
||
|
|
||
|
\subsubsection tracking Tracking
|
||
|
When a satellite is declared present, the parameters estimated by the acquisition module are then fed to the receiver tracking module, which represents the
|
||
|
second stage of the signal processing unit, aiming to perform a local search for accurate estimates of code delay and carrier phase, and following their eventual
|
||
|
variations.
|
||
|
|
||
|
Again, a class hierarchy consisting of a TrackingInterface class and subclasses implementing algorithms provides a way of testing different approaches,
|
||
|
with full access to their parameters.
|
||
|
|
||
|
|
||
|
\subsubsection decoding Decoding of the navigation message
|
||
|
Most of GNSS signal links are modulated by a navigation message containing the time the message was transmitted, orbital parameters of satellites
|
||
|
(also known as ephemeris) and an almanac (information about the general system health, rough orbits of all satellites in the network as well as data related to
|
||
|
error correction). Navigation data bits are structured in words, pages, subframes, frames and superframes. Sometimes, bits corresponding to a single parameter are
|
||
|
spread over different words, and values extracted from different frames are required for proper decoding. Some words are for synchronization purposes, others for
|
||
|
error control an others contain actual information. There are also error control mechanisms, from parity checks to forward error correction (FEC) encoding and
|
||
|
interleaving, depending on the system. All this decoding complexity is managed by a finite state machine implemented with the <a href="http://www.boost.org/libs/statechart/doc/tutorial.html" target="_blank">Boost.Statechart library</a>.
|
||
|
|
||
|
The common interface is TelemetryDecoderInterface.
|
||
|
|
||
|
\subsection observables Observables
|
||
|
GNSS systems provide different kinds of observations. The most commonly used are the code observations, also called pseudoranges. The <i>pseudo</i> comes from
|
||
|
the fact that on the receiver side the clock error is unknown and thus the measurement is not a pure range observation. High accuracy applications also use the
|
||
|
carrier phase observations, which are based on measuring the difference between the carrier phase transmitted by the GNSS satellites and the phase of the carrier
|
||
|
generated in the receiver. Both observables are computed from the outputs of the tracking module and the decoding of the navigation message.
|
||
|
This module collects all the data provided by every tracked channel, aligns all received data into a coherent set, and computes the observables.
|
||
|
|
||
|
The common interface is ObservablesInterface.
|
||
|
|
||
|
\subsection pvt Computation of Position, Velocity and Time
|
||
|
Although data processing for obtaining high-accuracy PVT solutions is out of the scope of GNSS-SDR, we provide a module that can compute a simple least square
|
||
|
solution and leaves room for more sophisticated positioning methods. The integration with libraries and software tools that are able to deal with multi-constellation
|
||
|
data such as <a href="http://www.gpstk.org" target="_blank">GPSTk</a> or <a href="http://gage14.upc.es/gLAB/" target="_blank">gLAB</a> appears as a viable solution for high performance, completely customizable GNSS receivers.
|
||
|
|
||
|
The common interface is PvtInterface. For instance, in order to use the implementation GpsL1CaPvt, add to the configuration file:
|
||
|
\code
|
||
|
;######### PVT CONFIG ############
|
||
|
PVT.implementation=GPS_L1_CA_PVT
|
||
|
\endcode
|
||
|
|
||
|
This implementation allows tuning of the following parameters:
|
||
|
\code
|
||
|
PVT.averaging_depth=10 ; Number of PVT observations in the moving average algorithm
|
||
|
PVT.flag_averaging=true ; Enables the PVT averaging between output intervals (arithmetic mean) [true] or [false]
|
||
|
PVT.output_rate_ms=100 ; Period in [ms] between two PVT outputs
|
||
|
PVT.display_rate_ms=500 ; Position console print (std::out) interval [ms].
|
||
|
PVT.dump=false ; Enable or disable the PVT internal binary data file logging [true] or [false]
|
||
|
PVT.dump_filename=./PVT ; Log path and filename without extension.
|
||
|
\endcode
|
||
|
|
||
|
\subsection output_filter Output filter
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|