diff options
author | Bogdan Radulescu <bogdan@nimblex.net> | 2018-02-03 13:30:58 +0100 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2018-02-03 13:30:58 +0100 |
commit | 3c177dbe3b93dc9a5db27f9b53417a28a1ead6ad (patch) | |
tree | f25c24b0d2127d0dc750e53e669e4d5c2e071116 /gr-digital/doc | |
parent | a0adcd3347c7ffd6ef3c42ce7705a23978774d3b (diff) |
Rename subdir doc to docs where appropriate
This makes the subdir naming consistent across modules.
Diffstat (limited to 'gr-digital/doc')
-rw-r--r-- | gr-digital/doc/CMakeLists.txt | 23 | ||||
-rw-r--r-- | gr-digital/doc/README.digital | 13 | ||||
-rw-r--r-- | gr-digital/doc/digital.dox | 502 | ||||
-rw-r--r-- | gr-digital/doc/packet_comms.dox | 653 |
4 files changed, 0 insertions, 1191 deletions
diff --git a/gr-digital/doc/CMakeLists.txt b/gr-digital/doc/CMakeLists.txt deleted file mode 100644 index 5383236da0..0000000000 --- a/gr-digital/doc/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2011 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. - -install( - FILES README.digital - DESTINATION ${GR_PKG_DOC_DIR} -) diff --git a/gr-digital/doc/README.digital b/gr-digital/doc/README.digital deleted file mode 100644 index f4d40f3a05..0000000000 --- a/gr-digital/doc/README.digital +++ /dev/null @@ -1,13 +0,0 @@ -This is the gr-digital package. It contains all of the digital -modulation blocks, utilities, and examples. To use the digital blocks, -the Python namespaces is in gnuradio.digital, which would be normally -imported as: - - from gnuradio import digital - -See the Doxygen documentation for details about the blocks available -in this package. A quick listing of the details can be found in Python -after importing by using: - - help(digital) - diff --git a/gr-digital/doc/digital.dox b/gr-digital/doc/digital.dox deleted file mode 100644 index 08e63008b3..0000000000 --- a/gr-digital/doc/digital.dox +++ /dev/null @@ -1,502 +0,0 @@ -/*! \page page_digital Digital Modulation - -\section digtial_introduction Introduction -This is the gr-digital package. It contains all of the digital -modulation blocks, utilities, and examples. To use the digital blocks, -the Python namespaces is in gnuradio.digital, which would be normally -imported as: - -\code - from gnuradio import digital -\endcode - -See the Doxygen documentation for details about the blocks available -in this package. - -A quick listing of the details can be found in Python after importing -by using: - -\code - help(digital) -\endcode - -\section digital_constellations Constellation Objects - -GNU Radio supports the creation and use of Constellation objects for -many of its digital communications needs. We define these -constellations with a set of constellation points in complex space and -the symbol mappings to those points. For a constellation that has 4 -symbols, it then has log2(4) = 2 bits/symbol. We define this -constellation with: - -<pre> - constel_points = [c0, c1, c2, c3] - symbols = [s0, s1, s2, s3] -</pre> - -In this case: \f$c_i \in C\f$ and \f$s_i \in [00, 01, 10, -11]\f$. Also, the mapping is a 1-to-1 for the items in both lists, so -the symbol \f$s_0\f$ is positioned in complex space at the point -\f$c_0\f$. - -In the code itself, the symbols are referred to as the -'pre_diff_code' since this is the mapping before the application of -differential modulation, if used. - -The constellation object classes are defined in constellation.h. There -is a hierarchy of classes for different purposes and which represent -special classes of constellations. The all derive from the virtual -class gr::digital::constellation. All constellations we will make are -based on classes derived from this base: - -<pre> -gr::digital::constellation - --> gr::digital::constellation_calcdist - --> gr::digital::constellation_sector - --> gr::digital::constellation_rect - --> gr::digital::constellation_expl_rect - --> gr::digital::constellation_psk - --> gr::digital::constellation_bpsk - --> gr::digital::constellation_qpsk - --> gr::digital::constellation_dqpsk - --> gr::digital::constellation_8psk -</pre> - -Each constellation class has a set of attributes and functions useful -for manipulating the constellations and for converting symbols to and -from complex points. One of the more important functions is the -gr::digital::constellation::decision_maker function that takes in a -sample in complex space and returns the symbol that it maps to. How -this calculation is performed generally distinguishes the -constellation classes from each other. - -The gr::digital::constellation_calcdist is the most generic -constellation class we can create. This takes in the constellation -points, symbol mapping, a rotational symmetry, and the number of -dimensions. The decision_maker function takes in a complex sample x -and calculates the Euclidean distance between x and each point in the -constellation map of the object. The constellation point that has the -minimum Euclidean distance to x is selected as the best match. The -decision_maker will then return the symbol value that matches to this -selected constellation point. - -We then have a concept of a constellation with a well-defined concept -of sectors in the gr::digital::constellation_sector. This is farther -refined if we know that the constellation is rectangular and can use -the gr::digital::constellation_rect class. These classes have an -overloaded decision_maker function that is specific to how the sectors -are defined in the constructor. Essentially, the decision making math -for this class is less costly than calculating the Euclidean distance -for each point in the space. So if we can sectorize our constellation, -using this class will be computationally cheaper. - -Finally, we have a set of pre-defined, hard-coded constellations for -BPSK (gr::digital::constellation_bpsk), QPSK -(gr::digital::constellation_qpsk), DQPSK -(gr::digital::constellation_dqpsk), and 8PSK -(gr::digital::constellation_8psk). These derive directly from -gr::digital::constellation and specifically overload the decision_maker -function. We have very simple metrics for calculating decisions for -each of these constellations. For BPSK, we simply slice on the real -axis. Samples are based solely on whether the real part of the complex -symbol x is greater than or less than 0. Similar, simple, decision -makers are defined for the others. - -Note that these specific constellations for the PSK modulations are -defined for only one mapping of the constellation points to the -symbols. Each is Gray coded, but for a specific Gray coding that is -hard-coded into the class. - - -\subsection digital_grc_constellations Constellation Objects in GRC - -GRC provides two constellation representations that we can use to more -easily define and interact with constellation objects. These are -located in the 'Modulators' category as 'Constellation Object' and -'Constellation Rect. Object'. These allow us to easily specify the -constellation points, symbol list, and other properties of the -constellation objects. They return the base() of the object, so the -variable's ID can be used directly with blocks that accept -constellation objects. - -These constellation blocks also allow us to specify the soft decision -LUT if using the constellation object for soft decision outputs. The -input can either be 'None' (default), a list of the soft bits that -were generated externally or by another function, or 'auto' where the -block will automatically calculate the soft decisions based on the -constellation points and symbol map. - - -\section digital_python_helpers Python Constellation Helper Functions - -A series of helper functions are defined in Python to create -different, common constellations. There are various functions that -have various levels of complexity in their definitions. - -\subsection digital_python_helpers_psk PSK Python Helpers - -There are two modules imported directly into gnuradio.digital. The -first is gr-digital/python/digital/psk.py and the second is -gr-digital/python/digital/psk_constellations.py. The -gr-digital/python/digital/psk.py module defines the following -constellations: - -<pre> - psk_constellation(m, mod_code, differential) -</pre> - -This function defines a PSK modulation of order 'm' (that is, there -are m number of constellation points / symbols). The 'mod_code' is -either mod_codes.GRAY_CODE or mode_codes.NO_CODE to set the symbol -mapping up as either Gray coded or not. The 'differential' argument is -either True to use differential coding or False for non-differential -coding. - -This function creates and returns a constellation object that can then -be used by any block that takes a constellation -(gr::digital::constellation_decoder_cb, -gr::digital::constellation_receiver_cb, -gr::digital::constellation_soft_decoder_cf, or -gr::digital::lms_dd_equalizer_cc). - -The gr-digital/python/digital/psk.py module also holds functions -similar to digital.psk_constellation but that create a full modulator -and demodulator chain derived from digital.generic_mod_demod. - -<pre> - psk_mod(constellation_points, mod_code, differential, *args, **kwargs) - psk_demod(constellation_points, mod_code, differential, *args, **kwargs) -</pre> - -The args and kwargs are parameters of the generic_mod or generic_demod -passed directly to them. See \ref digital_generic_mod_demod for -details of this interface. - -There is another Python file full of helper functions to create -different constellations. This is found in the -gr-digital/python/digital/psk_constellation.py file. This file -provides functions that build the vectors of constellation points and -symbol mappings that can be used to create a constellation -object. These are particularly helpful when using the Constellation -Obj. and Constellation Rect. GUI elements in GRC. - -The gr-digital/python/digital/psk_constellation.py file has extensive -documentation that describes the naming scheme used for the different -constellations that will not be repeated here. The main thing to -understand is that these functions define constellations of the same -order with different Gray code mappings. The function names are: - -<pre> - (const_points, symbol_map) = psk_M_0xk_<permutation>() -</pre> - -Where M is the order of the modulation (2 for BPSK, 4 for QPSK, -etc.), and k and \<permutation\> define a particular encoding for the -Gray code mapping used. The documentation in the file explains how -these two concepts define the Gray code mapping. - -These functions are also simply named "psk_M_n" when n is an integer -from 0 to N-1 for however many mappings are defined for that -modulation. Not all modulations are fully defined, and the value -for n has no other meaning except as a counter. - -The functions return a tuple of lists. The first list in the tuple is -the list of complex constellation points and the second list contains -the symbols mapped to those points. These lists can then be passed to -a constellation class directly to create a constellation of any Gray -code mapping needed. - -While not all Gray code mappings of the modulations are defined, there -is a generator function to automatically build any rotation of a basis -constellation: - -<pre> - (const_points, symbol_map) = \ - constellation_map_generator(basis_cpoints, basis_symbols, k, pi) -</pre> - -We provide a basis constellation map and symbol map as the fundamental -rotation of the constellation points. This function uses the k and pi -inputs (see the discussion in psk_constellation.py for what these -mean) to return a new rotation of the constellation's symbols. If the -basis symbols are Gray coded than the output symbols will also be Gray -coded. Note that this algorithm specifically depends on the -constellation in complex space to be square to preserve the Gray code -property. - - -\subsection digital_python_helpers_qam QAM Python Helpers - -Similar to defining PSK modulations, GNU Radio also has helpers for -some QAM modulations, found in gr-digital/python/digital/qam.py and -gr-digital/python/digital/qam_constellations.py. Similar functions to -what has been described for PSK exist here: - -<pre> - qam_constellation(constellation_points, differential, mod_code, - large_ampls_to_corners) - qam_mod(constellation_points, differential, mod_code, *args, **kwargs) - qam_demod(constellation_points, differential, mod_code, - large_ampls_to_corner, *args, **kwargs) -</pre> - -The parameters to these functions is the same as for the PSK -equivalents. The new argument 'large_ampls_to_corner' is defined in -the documentation as: - -<pre> - large_ampls_to_corners: If this is set to True then when the - constellation is making decisions, points that are far outside - the constellation are mapped to the closest corner rather than - the closet constellation point. This can help with phase - locking. -</pre> - -Similarly, gr-digital/python/digital/qam_constellations.py defines a of -QAM constellation functions that return a tuple containing the -constellation points and the symbol mappings. The naming scheme is -defined in depth in the module itself and is similar to the equivalent -set of PSK functions. - -Currently, only a subset of 16QAM symbol mappings are defined, but we -can use of the constellation_map_generator function described in the -previous section to define more mapping rotations for and square QAM -modulation. - - -\section digital_generic_mod_demod The Generic Modulator/Demodulator -Hierarchical Blocks - -Since digital modulation and demodulation are complex functions, the -different parts can be done by different existing GNU Radio blocks. We -have combined these into a generic modulator and generic demodulator -hierarchical blocks to make access and use much easier. This file can -be found as gr-digital/python/digital/generic_mod_demod.py. - -\subsection digital_generic_mod Generic Modulator - -The modulator constructor looks like: - -<pre> - digital.generic_mod(constellation, differential, samples_per_symbol, - pre_diff_code, excess_bw, verbose, log) -</pre> - -The 'constellation' arg is a constellation object as defined above in -\ref digital_constellations and can represent any constellation -mapping. The 'differential' arg is a bool to turn differential coding -on/off. The block also performs pulse shaping and interpolates the -pulse-shaped filter to some number of 'samples_per_symbol'. The pulse -shaping is a root raised cosine filter defined by the excess -bandwidth (or alpha) parameter called 'excess_bw.' - -We can also turn on a verbose mode to output information to the -user. The 'log' parameter toggles logging data on/off. When logging is -turned on, it stores every stage of the modulation to a different file -so that each stage can be independently analyzed. - - -\subsection digital_generic_demod Generic Demodulator - -The demodulator looks like: - -<pre> - digital.generic_demod(constellation, differential, samples_per_symbol, - pre_diff_code, excess_bw, freq_bw, timing_bw, - phase_bw, verbose, log) -</pre> - -The additional parameters to the demodulator are the loop bandwidths -for the different signal recovery loops used internally. There are -separate loops for frequency acquisition, timing acquisition, and fine -frequency / phase acquisition, controlled in tern by each of the -three 'X_bw' arguments. Otherwise, the arguments are the same as the -modulator. - - -\subsection digital_generic_guts Guts of the Modulator and Demodulator - -The generic modulator looks like the following: - -<pre> - blocks.packed_to_unpacked_bb: takes in packed bytes - digital.map_bb: maps baseband symbols to the pre-differential encoding - digital.diff_encoder_bb: differentially encode symbols - digital.chunks_to_symbols_bc: convert symbols to complex samples - filter.pfb_arb_resampler_ccf: perform upsampling to samps/symbol and pulse shape -</pre> - -The mapping and chunks-to-symbols stages are done using the -information provided by the constellation object. - -Note that the modulator takes in packed bytes, which means that all 8 -bits per byte are used and unpacked into k bits per symbol. - -The generic demodulator looks like the following: - -<pre> - digital.fll_band_edge_cc: Performs coarse frequency correction - digital.pfb_clock_sync_ccf: Matched filtering and timing recovery - digital.constellation_receiver_cb: Phase tracking and decision making (hard bits) - digital.diff_decoder_bb: Differential decoding - digital.map_bb: Map to pre-differential symbols - blocks.unpack_k_bits_bb: Unpack k bits/symbol to a stream of bits -</pre> - -This block outputs unpacked bits, so each output item represents a -single bit of data. A block like 'pack_k_bits' can be used following -this to convert the data back into bytes. - - -\section digital_constellation_modulator Constellation Modulator - -The Constellation Modulator, Constellation Receiver, and Constellation -Decoder can all take Constellation Objects to define what they are -meant to transmit and receive. - -The gr::digital::constellation_modulator block takes as a parameter -the reference to the constellation object. The block is very generic -in that the mapping from bits to symbols is done based on the -constellation object passed to it. The modulator block requires packed -bits as the input stream (that is, all 8 bits of the stream contain -information). - -The other parameters of this block include a setting as to whether or -not to differentially encode the symbols, the number of samples per -symbols, and the excess bandwidth of the transmitted pulse-shaped -signal. - -We can set up the transmitter using the constellation modulator block -and use the same constellation object at the receiver so we know the -same constellation settings are being used. - -\section digital_softbits Support for Soft Decisions - -To support soft decisions of the receivers instead of the current hard -decisions, the constellation objects also accept a soft decision -look-up table (LUT) or can be told to generate a LUT based on the -constellation points and symbol map. - -All constellation objects can accept a new LUT using the -gr::digital::constellation::set_soft_dec_lut function. This function -takes in a LUT, which is a vector of floating point tuples (in C++ it -is just a vector\<vector\<float\>\>) and a precision value that -specifies how accurate the LUT is to a given number of bits. - -The constellation objects also have two functions to calculate the -soft decisions from their constellation and symbol map. The -gr::digital::constellation::calc_soft_dec takes a complex number (and -optional noise power) and returns the soft decisions as a list of -floats. This function is used internally in the -gr::digital::constellation::gen_soft_dec_lut, which takes in the LUT's -precision (as a number of bits) and an optional noise power estimate, -if known. This function calculates the soft decisions itself. These -functions are very expensive because each constellation point is taken -into account during the calculation. We provide the -gr::digital::constellation::set_soft_dec_lut in order to allow users -to use one of the many known approximations to more quickly generate -the soft decision LUT. - -The gr::digital::constellation::calc_soft_dec function could be used -instead of drawing directly from a LUT, which is probably only -important if the noise floor or channel estimates are likely to change -and we want to account for this in the decisions. The basic -implementation of the soft decision calculation is the full -calculation based on the distance between the sample and all points in -the constellation space. If using this function for real-time -decisions, a new object should inherit from the -gr::digital::constellation class (or whichever child class is being -used) and redefine this function with a faster approximation -calculation. - -Note: If no soft decision LUT is defined but -gr::digital::constellation::soft_decision_maker is called then the -full calculation from gr::digital::constellation::calc_soft_dec is -used by default. - -The LUT is a list of tuples, where each index of the list is some -quantized (to some number of bits of precision) point in the -constellation space. At each index, there is a tuple of \e k soft -bit values for a constellation with \e k bits/symbol. - -To help with this, the file -gr-digital/python/digital/soft_dec_lut_gen.py can be used to create -these tables. The function digital.soft_dec_table_generator(generator, -precision) function generates a LUT based on some generator function -and the number of bits of precision required. This file contains -documentation explaining the system better. Or the -digital.soft_dec_table(constel, symbols, prec, npwr=1) can be used -which takes in the constellation map and symbols to do the full raw -calculation of the softbits as opposed to a generator function. - -To further aid the LUT creation, the digital module also defines a -number of functions that can be used as soft decision generators for -the soft_dec_table function. These functions are found in -psk_constellations.py and qam_constellations.py. These files were -already mentioned as they contain a set of functions that return -tuples of constellation points and Gray-mapped symbols for different -modulations. But these files contain a second set of functions -prefixed by 'sd_' which are soft decision LUT generator functions Each -LUT generator takes in a complex value and returns the tuple of soft -decisions for that point in complex space. To aid with this, -soft_dec_lut_gen.py defines a 'calc_from_table' function that takes in -a complex sample, the precision of the table, and the LUT itself and -returns the tuple of soft decisions in the LUT that is closest to the -given symbol. Each of these functions can be found directly from the -'digital' Python module. - -The LUTs are defined from min to max constellation points in both the -real and imaginary axes. That means that signals coming in outside of -these bounds are clipped to 1. So there is no added certainty for -values beyond these bounds. - -The gr::digital::constellation_soft_decoder_cf block takes in a -constellation object where a soft decision LUT is defined. It takes in -complex samples and produces a stream of floats of soft decisions. The -soft decision outputs are not grouped together, it is just a stream of -floats. So this block acts as an interpolator that takes in 1 complex -sample and return \e k float for \e k bits per symbol. - - -\subsection soft_dec_api Review of the Soft Decision API/Functions - -Files of interest: -\li psk_constellations.py: PSK constellations and soft decision generators -\li qam_constellations.py: QAM constellations and soft decision generators -\li soft_dec_lut_gen.py: Functions to build soft decision LUTs and test them -\li test_soft_decisions.py: A script that generates a random complex -sample and calculates the soft decisions using various methods. Plots -the sample against the full constellation. Requires matplotlib installed. - -Functions: -\li digital.sd_psk_2_*: Returns (constellation, symbol_map) lists for -different rotations for BPSK. -\li digital.sd_psk_4_*: Returns (constellation, symbol_map) lists for -different rotations for QPSK. -\li digital.sd_qam_16_*: Returns (constellation, symbol_map) lists for -different rotations for 16QAM. -\li digital.soft_dec_table_generator: Takes in a generator function -(like the digital.sd_XXX above) and creates a LUT to a specific precision. -\li digital.soft_dec_table: Takes in a constellation/symbol map and -uses digital.calc_soft_dec to generate a LUT to a specific precision. -\li digital.calc_soft_dec: Takes a complex sample and calculates the -soft decisions for a given constellation/symbol mapping. -\li digital.calc_soft_dec_from_table: Given a sample and a LUT, -returns the soft decisions of the LUT for the nearest point to the -sample. - -C++ Interface: -\li gr::digital::constellation::gen_soft_dec_lut: uses calc_soft_dec -to internally generate a soft decision LUT. -\li gr::digital::constellation::calc_soft_dec: calculates the soft -decisions for a given sample from the full constellation/symbol map. -\li gr::digital::constellation::set_soft_dec_lut: Set the soft -decision LUT from an externally-calculated LUT. -\li gr::digital::constellation::has_soft_dec_lut: has the LUT been -set/generated or not. -\li gr::digital::constellation::soft_decision_maker: Used by -gr::digital::constellation_soft_decoder to convert samples to soft -decisions. If a LUT is defined, uses it; else, uses calc_soft_dec. - - -*/ diff --git a/gr-digital/doc/packet_comms.dox b/gr-digital/doc/packet_comms.dox deleted file mode 100644 index 9b9f59fbd7..0000000000 --- a/gr-digital/doc/packet_comms.dox +++ /dev/null @@ -1,653 +0,0 @@ -/*! \page page_packet_comms Packet Communications - -\section packet_introduction Introduction - -This page describes... - -The point of these examples and the work is to provide a canonical -tool for exploring burst digital communications. Providing the entire -PHY chain in GRC is to help us more easily explore and extract -portions of the transmit and receive chains to better understand, -tweak, and optimize the system. - - -\section packet_tx Understanding the Transmitter - -The transmitter PHY layer defines the following properties of the -transmitted frame: - -- Data integrity check, generally a \ref gr::digital::crc32_async_bb - "CRC". Standard practice would be to calculate a CRC32 of the - payload and append this to the end of the frame. - -- \ref page_fec "Forward Error Correction (FEC)". For correcting bit - errors during reception, we use FEC codes, which have different - properties for complexity, correcting capabilities, and amounts of - added redundancy. See our \ref page_fec "FEC-API page" in the manual - for more on how to use these and what types of codes are already - available. - -- Frame formatting. We expect the data to have been delivered to the - transmitter from some higher layer (MAC/Network), which we treat as - the payload. The PHY layer then puts on a bit of its own framing in - order to properly transmit it for other radios to receive - correctly. This often involves some information about the payload - format, such as the length, the type of FEC code used, and the type - of modulation or modulation parameters. The PHY layer frame will - also often add a known word to the front to help with - synchronization and identification. We use the Packet Header - Formatter block for this, which is completely defined by a packet - formatter object. See the gr::digital::header_format_base class - to understand more about how these formatters are created and used. - - The \ref gr::digital::protocol_formatter_async "Protocol Formatter" - has two output paths, both emitted as PDUs from message ports. The - first message port is "header" that emits the header created for the - payload based on the formatter object. The second message port is - "payload" which is just the input payload PDU re-emitted. This - creates two paths, which allows us to separately modulate the header - and payload differently as well as encode the header with a - different FEC code. We often want to do this to provide a much - simpler and more robust modulation and FEC structure to the header - to ensure that it is correctly received and then use a different - modulation and code for the payload to maximize throughput. - - NOTE: If the header formatter adds the known word / access code - here, and then we apply an FEC code to the header, then we have the - problem that the known word is also encoded. The receiver must be - made aware of this and correctly look for the encoded known - word. The packet_tx hier block example is a case where this - happens. If we use a repetition encoder, the access code is now - three bits out for every bit in. The packet_rx receiver example has - to account for this in the Correlation Estimator block that is - correlating against the known word. - -- Modulators. We create a modulator path for both the header and - payload. We define the operations of these two paths completely - using a \ref gr::digital::constellation "Constellation Object" (see - the \ref digital_constellations "Digital Modulation" manual page for - more information). The constellation objects define the mapping from - bits to complex symbols. You can use these objects in various ways, - but the packet_tx.grc example provides one way. After moving from - the PDU to tagged stream mode, the \ref gr::blocks::repack_bits_bb - "Repack Bits block" takes the packed 8-bits/byte data and converts - this into "chunks" of the number of bits per symbol of the - modulation (using the \ref - gr::digital::constellation::bits_per_symbol() "bits_per_symbol()" - property of the constellation object). We then map these chunks into - some known mapping function, most often a form of Gray Coding, using - the \ref gr::digital::map_bb "Map block" and the constellation object's \ref - gr::digital::constellation::pre_diff_code() "pre_diff_code()" - function. We then move these remapped chunks to complex symbols, - again as defined by the constellation object through the \ref - gr::digital::constellation::points() "points()" function in the - \ref gr::digital::chunks_to_symbols_bc "Chunks to Symbols block". - -- Combine the header and payload. We need to take both the header and - payload paths back together into a single stream. In packet_tx.grc, - we are working with tagged streams, so both paths keep track of the - size of their segments. Using the Tagged Stream Mux block, we - recombine these two paths into one. - -- Burst Shaping and Filtering. The next stage shapes the packet for - burst transmission. We apply two blocks to shape the burst - appropriately. - - First, the \ref gr::digital::burst_shaper_cc "Burst Shaping block" - handles the structure of the burst by applying two different forms - of padding. First, there is a window that is applied to the time - domain of the burst. This involves a ramping up stage from 0 and a - ramping down stage back to 0. We define a window as a vector, and - the \ref gr::fft::window "fft.window" set of window functions is - useful here, such as using a Hann or Kaiser window. The size of the - window is split in half to apply the left half of the window for the - ramp-up and the right half of the window for the ramp-down. The - window has two different modes: to insert or not insert phasing - symbols. When inserting phasing symbols, a sequence of 1's and -1's - is inserted for the duration of the ramp-up and ramp-down - periods. So a window size of 20 will produce 10 alternative 1's and - -1's on the front of the burst and another 10 alternating symbols on - the rear of the burst. The window is then applied to these phasing - symbols and does not affect the burst symbols directly. If we are - not using the phasing symbols, the the window is applied to the - front and back of the burst directly. - - The Burst Shaper can also add padded 0's to the front or back of the - burst. This allows us to provide some extra control over the - structure of the burst. In particular, it can be useful to add - post-padding 0's that is the length of the delay of the pulse - shaping filter that will come next. This makes sure that the full - burst of samples is pushed through the filter and transmitted - completely. - - -\verbatim - ____________________ - / \ - / \ - / \ - ______/ \____ - | E | D | C | B | A | - - A: Pre-padding 0's - B: Ramp-up window - C: Frame - D: Ramp-down window - E: Post-padding 0's -\endverbatim - - - When using phasing symbols, C is the entire frame and sections B - and D are filled with alternative 1's and -1's. - - When not using phase symbols, the frame extends B through C to D. - - After creating this burst shape, we then put the burst through a - pulse shaping filter. This filter both shapes the complex samples - into appropriate symbols for transmission based on a spectral mask - as well as up-samples the burst to the specified number of samples - per symbol. In packet_tx, we are using a Polyphase Arbitrary - Resampler to perform this task for us, which means that we can - specify and real value for the number of samples/symbol, as long as - it is greater than or equal to 2.0. - - Typical pulse shape filters are \ref - gr::filter::firdes::root_raised_cosine "Root Raised Cosine (RRC)" - filters and \ref gr::filter::firdes::gaussian "Gaussian" filters. - - Because the pulse shape filter up-samples, in packet_tx, we use a - \ref gr::blocks::tagged_stream_multiply_length "Tagged Stream Multiply Length Tag block". - The resampler block knows nothing about - tagged streams, so when it up-samples, the \ref - page_tagged_stream_blocks "tagged stream block (TSB)" tag value does - not change. We need to change this tag's value, too, and so we use - the multiply length tag block for this purpose. This is helpful when - working with UHD devices, like in uhd_packet_tx.grc, because we can - explicitly tell the UHD USRP Sink block to expect a tagged stream to - manage the transmission of the burst. - -\subsection packet_tx_params Parameters of the packet_tx Example - -The canonical example for handling narrowband M-PSK or M-QAM is the -packet_tx.grc hierarchical block. - -- Header FEC Code (hdr_enc) -- Payload FEC Code (pld_enc) -- Header Constellation Object (hdr_const) -- Payload Constellation Object (pld_const) -- Protocol Formatter Object (formatter) -- Samples per symbol (sps as a float) -- Pulse shaping filter (psf_taps, designed for the polyphase arbitrary - resampler) - -We can see all of these objects and settings in the -packet_loopback_hier.grc example and uhd_packet_tx.grc if using a -UHD-compatibly radio front end. - -\subsection packet_tx_examples Examples - -The following examples exist to showcase how to control each stage of -the transmit processing. - -- tx_stage0.grc: simple creation of PDUs to input into the - transmitter. By default, this generates \ref gr::blocks::random_pdu - "random PDUs" for testing. However, we can switch in the \ref - gr::blocks::tuntap_pdu "TUNTAP PDU" block to create a tun or tap - device as the input of samples from some OS application. Note that - you will need root privileges to create a tun/tap device and - configure it. - - -- tx_stage1.grc: Adding a CRC to the frame. The Message Debug prints - the before and after adding the \ref gr::digital::crc32_async_bb - "CRC32", so we can see the original PDU and then the PDU with the - added 4 bytes of check. - - -- tx_stage2.grc: Adding \ref page_fec "forward error correction". This - adds an \ref gr::fec::async_encoder "FEC Async Encoder" block to - compare pre- and post-encoding. Three different FEC encoders are - available immediately in this example with the repetition encoder - enabled by default. This encoder just repeats every bit 3 times, so - it is easy to see the behavior before and after encoding. Simply - disable this FEC code and enabling one of the others will change the - encoding behavior. - - -- tx_stage3.grc: takes the payload with the CRC32 check and creates - the packet structure. Both the header and payload are printed out, - where the payload is the input payload+CRC and the header is defined - by the 'formatter' object. The default formatter just applies an - access code (using the default 64-bit - digital.packet_utils.default_access_code code) and then it - calculates the payload length (in bytes) as a 16-bit value. This - 16-bit length field is duplicated, so in the receiver it can check - both 16-bit fields to make sure they agree. This formatter also - takes a threshold value. The transmitter does not use this - threshold. That parameter is used in the receiver to know how many - bits can be wrong in the access code and still pass. - - Disabling the \ref gr::digital::header_format_default - "default header definition" and enabling the other 'formatter' to - change the protocol. This other protocol definition is the \ref - gr::digital::header_format_counter "counter header". It adds the - access code and payload length fields as the header like the default - formatter. This formatter includes two other fields as well: the - number of bits/symbol used in the payload modulator (as a 16-bit - field) and a 16-bit counter. Each packet transmitted increments this - counter by 1, which means we can keep track of how many packets we - have sent and/or received. - -- tx_stage4.grc: Here we add the modulation to both the header and - payload paths, defined by the hdr_const and pld_const objects, - respectively. Both are defined as BPSK constellations by - default. The output is shown in two \ref page_qtgui "QTGUI display" - graphs. We see the samples in time first, and this is triggering off - the TSB tag "packet_len". When the time display updates, we can see - the same pattern right after the tag, which is the header, and then - the changing samples are the random values in the payload. - - When we look at this Freq tab of this example, we just see a mostly - flat frequency response over the entire frequency range. This - response is due to the samples just being +1's and -1's with no - transition between them and sampled at 1 sampler per symbol. This is - not something that we can just transmit as a burst. The square - pulses we use provide horrible out-of-band (OOB) emissions if we put - this over the air directly, and each burst would go from 0 to +/-1 - within the coarse of a single sample, which again provides large OOB - emissions. We need to shape the bursts properly from here. - -- tx_stage5.grc: Adds the \ref gr::digital::burst_shaper_cc "Burst Shaper" - block. The default parameters are to use a Hann window of 50 symbols - and to add 10 0's as pre- and post-padding. We can adjust any of - these values to explore what the output burst looks like. We can - stop the time sink from updating and turn on the markers for the - Re{Data 0} channel to easily count the samples and observe the - effect of the window. - - As an aside, the window of 50 produces 25 phasing samples on either - side. This is a lot, but we did this to help show off the way the - window looks a bit more clearly. - -- tx_stage6.grc: We then need to up-sample the signal by the number of - samples/symbol (sps) and apply our pulse-shaping filter. Again, we - are using some larger numbers than we really would in an actual - scenario to make it visually clear what is happening. The psf_taps - filter creates an RRC filter designed for the 32-arm (set by nfilts) - polyphase filterbank resampler. In this RRC Filter Taps object, we - set the number of taps to be 15*sps*nfilts. The sps and nfilts are - properties of the sample stream and upsampling factor. The value 15 - is the number of symbols to represent in this filter; basically that - we are going to look over the history effects of 15 samples to - manage the inter-symbol interference (ISI). That is a long RRC filter - but done so to make the simulation look better. Five or seven is a - more realistic value. Similarly, we set sps=4 here to make the time - and frequency plots look better. Normally, we would want this closer - to 2. - - Now looking at the time domain plot, we see the filtered samples, - which are not as pretty as before. They have over- and under-shoots, - and if we turned on the line markers, we would not see the original - bits easily through this. That is the effect of the RRC filter, - which introduces ISI into the transmitted stream. However, when we - look at the frequency domain, we see a much better shape, which we - can transmit as part of our channel assignment. - -- tx_stage6a.grc: An aside here to study the RRC filters more. This - example adds a second RRC filter (without any resampling) that - matches the transmitter's RRC filter. The matched filter means that - the samples are filtered by two RRC filters, which together make a - raised cosine (RC) filter. This RC filter is what is known as a - Nyquist filter and has the properties of 0 (or very close to 0) - ISI. Though we introduced ISI in the transmit RRC filter, the second - stage at the receiver undoes that ISI making for a clean, filtered - signal. Turning on marker in the time domain shows two clean lines - at +1 and -1. The receiver just needs to know which of the sps - samples to grad to get the original symbol that was transmitted. But - that is the job of the receiver. - -At this point, we have an encoded, modulated, and shaped burst ready -to be transmitted out of a radio. The uhd_packet_tx.grc example puts -all this together, where we have packaged up most of the transmitter -behavior into packet_tx.grc. We then generate random PDU's, put them -through the packet_tx block, and then through a Multiply Const block -and into a USRP sink. The Multiply Const block is used for digital -scaling of the signal to allow us power control on top of the -transmitter gain inside the USRP radio itself. - - -\section packet_rx Understanding the Receiver - -The receiver is far more complicated. The work involved here is -largely in the detection and synchronization of the received -frames. We must assume that frames are coming in as bursts with -potentially random time intervals. - -It is important to understand that it is very difficult to make a -simple protocol work in all scenarios. We have to assume that some -packets will be lost through either a missed detection at the start or -poor synchronization statistics during processing of the burst. - -The generic receiver example can be found in packet_rx.grc. This hier -block provides the main detection, synchronization, header/payload -management, demodulation, and decoding of the PHY frames. The input to -this hier block should be not be too far off in frequency. The GNU -Radio block \ref gr::digital::fll_band_edge_cc "FLL Band-Edge" tends -to work well enough, though this is unnecessary if the radio are -synchronized in frequency some other way (e.g., with a GPSDO such as -is available on USRPs). - -The main flow of samples here is to detect a frame by discovering its -known word, which also provides initial estimates on timing and phase -offsets of the received frame. We then go through a clock sync block -to perform matched filtering and sample time correction to produce -resampled symbols at 1 sample/symbol. Now we have samples that are -split between the header and payload. We might have information inside -of the header that helps the receiver understand the payload. For -instance, the length of the payload is generally encoded in the -header. So we have to demux the header and payload. - -We assume that we know the length of the header in symbols, which we -pass on to the header demodulator chain. Knowing the header -modulation, we synchronize the phase and frequency, demodulate the -symbols into soft bits, decode those soft bits based on the known -header's FEC code, and then parse the header information. The header -parser extracts information about the payload, such as the number of -symbols in the payload and possibly the number of bits/symbol used in -the payload modulation. - -The \ref gr::digital::header_payload_demux "Header/Payload Demux" -block sends the appropriate number of samples to the payload demod -chain. This chain does its own phase/freq synchronization for the -appropriate constellation used in the payload, decodes the samples to -soft bits, performs the FEC decoding, and then does the CRC32 -check. If this passes, the payload is sent out of the hier block as a -PDU with the PHY layer framing stripped. - -When looking at the packet_rx.grc example, notice that we have -instrumented a number of debug ports along the way. These ports are -designed to make it possible for us to externally hook up graphing and -debug blocks in whatever way we are comfortable with to see the signal -along the path and more easily debug. - - -\subsection packet_rx_correst Correlation Estimator - -The first stage of the receiver searches for the known word prepended -to every burst from the transmitter. The known word has gone through -two stages of processing: encoding with the header's FEC (optional) -and modulated by the header's modulator. The correlation of the known -word is done at the input sample stage, so we have to recreate the -modulated and possible encoded known word at the receiver. - -To simplify dealing with the encoding process, in packet_rx.grc, we -assume one of two types of codes: dummy code (or not coded) and a 3x -repetition code. We then just simply calculated the preamble's bits -for both cases. Depending on the header decoder (hdr_dec) used, the -hier block knows which preamble to use. - -Next, we need to take the known, encoded word and modulate it with the -header's modulator and pulse shaping filter. We create a simple -modulator in the variable 'rxmod' that takes the header \ref -gr::digital::constellation "constellation object" (hdr_const), the -number of samples per symbol, and the pulse shape filter's bandwidth -parameter (eb). The \ref gr::digital::modulate_vector_bc "Modulate Vector" -block than combines this 'rxmod' modulator with the 'preamble' -known word into a vector of complex symbols, here called -'modulated_sync_word'. This variable is then passed to the \ref -gr::digital::corr_est_cc "Correlation Estimator" block. - -One tricky thing about burst communications and network setups is the -power of the received samples is unknown and time varying. It is -preferential to try to auto-detect the burst and scale the signal to -+/-1 before coming in to packet_rx. There is still a lot of work to be -done for AGC loops in the hardware and automatic scaling in -software. The Correlation Estimator tries to deal with this. We use a -threshold as an approximate probability of detection. This value -should be set very high; the default here is 99.9%. The correlation -tends to scale well as the amplitudes change and for relatively low -SNR conditions. Still, it is always possible to miss a detection event -or have a false positive. - -Another thing that the Correlation Estimator can do for us is provide -information for digital scaling the samples. When received over -hardware, the signals tend to be very small, but most of our follow-on -processing assumes they are about +/-1. The Correlation Estimator -finds the amplitude of the sample where the correlation peak was -found, inverts it, and sends it as a tag with the key 'amp_est'. We -can use this down stream to adjust the amplitude by rescaling the -samples from this value. For our packet_rx example, we use the \ref -gr::blocks::multiply_by_tag_value_cc "Multiply by Tag Value" block, -which updates its multiplicitive factor based on the tag. Much of this -could be handled by a good AGC routine in the hardware. - -Finally, the main purpose of the Correlation Estimator block is to -provide the down-stream synchronization blocks with initial estimates -of the timing and phase offset. The peak of the magnitude of the -correlation event corresponds to the sampling timing of the data -stream. - -\verbatim - 1. /\ 2. _ - / \ / \ - __/ \__ __/ \__ -\endverbatim - -The above two drawings show two different correlation scenarios. In -scenario 1, the timing is exact and the sample at the peak of that -curve is the proper sample time of the last symbol of the known -word. In scenario 2, there is a timing offset where the correct timing -offset is half-way between two samples. This would be a timing offset -of 0.5 (or -0.5). Knowing where that estimated offset is helps our -timing recover blocks start near the correct sample offset and then -track from there. - -The magnitude of the correlation helps us discover the timing -offset. The correlation itself is a complex vector. So where the peak -of the magnitude happens, we can look to the complex value of the -correlation at the same point and the phase difference between the -real and imaginary parts is the phase offset of the signal. - -The Correlation Estimator block calculates the time and phase offsets -and creates stream tags for "time_est" and "phase_est". It also -creates two other tags: "corr_start" and "corr_est," both of which -contain the value of the peak of the magnitude of the -correlation. Because there is a delay in the correlation algorithm -that is affected by the size of the correlation, we need to adjust -where the correlation event occurs to where the tags are actually -placed on the output stream. The block places the "corr_start" tag on -the sample where the correlation actually occurred. It then places the -other three tags offset by some "Tag marking delay," which is a -user-calculated value to place the tags at the correct spot in the -data stream for the actual start of the known word's first symbol. - -In packet_rx, we empirically discovered the tag marking delay for -different values of the samples/symbol ('sps') variable and made a -list 'mark_delays' that is index by 'sps' to properly set 'mark_delay' -for the start of the known word. Getting is correct has a huge effect -on the timing recover loop, which can take a while to converge if it -starts offset in time by a sample. - -See the example example_corr_est.grc to explore the Correlation -Estimator blocks more. - - -\subsection packet_rx_timing Timing Recovery - -After detecting the frame and estimating the time and phase estimates, -we have to actually perform the timing synchronization step. The -packet_rx example uses the -\ref gr::digital::pfb_clock_sync_ccf "Polyphase Clock Sync" block to -do this. This PFB clock sync (PCS) block typically performs blind -timing recovery on a series of samples. It is composed of 'nfilt' -filters in a filterbank where each filter represents a different phase -from [0, 2pi) in steps of 2pi/nfilts. The algorithm finds the correct -arm of the filterbank that corresponds to the time shift of the -samples. It also knows to look for a "time_est" stream tag and use -that information to set its phase arm estimate. If we have a time -estimate like scenario 1 above, we have perfect timing and so would -select the 0th arm of the filterbank. In scenario 2, we are off by -half a sample, so we select arm nfilts/2. The PCS is a tracking loop, -so it will start with the initial estimate and then keep track of the -timing as well as hone-in on actual timing information of the symbol -stream. - -The PCS block uses a filterbank concept to perform its tracking -operation. The filters within the filterbank operate best when they -are phase offsets of the matched filter. So not only does the -block recover the timing, it also performs the matched filtering and -produces the optimal 1 sample/symbol output. These are then optimally -sampled symbols in the complex constellation space. They need to be -mapped back to bits and decoded. But first, we need to parse the -header in order to discover information about the payload. - -See the example example_corr_est_and_clock_sync.grc to play with the -parameters of time synchronization. - - -\subsection packet_rx_hpd Header/Payload Demux - -Because the header and payload can be modulated differently, the rest -of the symbol processing has to be split into two chains. We do this -using the \ref gr::digital::header_payload_demux "Header/Payload Demux" -block (HPD). We assume that we know the protocol, and so the format, -coding, and modulation of the header. Generally speaking, these are -all controlled through three different objects: - -- formatter: An object that described the header structure, derived - from gr::digital::header_format_base. - -- hdr_const: An object that describes the bit and symbol mapping, - derived from gr::digital::constellation. - -- hdr_dec: An object that describes the FEC code, derived from - gr::fec::generic_decoder. - -Through these, we can ask for any parameter to set up the following -stages of processing. - -The HPD block is fairly complicated and we will only use it in one -kind of configuration here. See the manual page for the \ref -gr::digital::header_payload_demux "HPD" block itself for more -details. In our use of the HPD block, it receives the data stream and -looks for a Trigger Tag Key. We will use 'time_est', one of the tags -produced by the Correlation Estimator to indicate the sample that -starts the header. When the HPD block sees this trigger key, it passes -along a known number of symbols out of the 'header' stream port. We -know the number of symbols based on the formatter, constellation, and -FEC decoder objects. The formatter objects knows the number of bits in -the header via the header_nbits() function, the constellation knows -how many bits per symbol (via bits_per_symbol()), and the FEC decoder -knows the encoding rate (via 1/rate()). The number of symbols in the -header is therefore: - - (header_nbits() * 1/rate()) / bits_per_symbol() - -The HPD then sends this many symbols on to be processed. It holds up -any more processing until triggered to do so with information through -the 'header_data' input message port. The header processing chain will -end with the Packet Parser producing the message here. - -When the 'header_data' input message port receives valid information, -it releases the payload out of the 'payload' stream port. The main -thing that the 'header_data' input message port receives is -information about the length of the payload. The HPD parameter 'Length -tag key' is matched to the message received in 'header_data', which is -then used to gate the output of samples as the payload. In our case, -we specify the length as the number of symbols through the message key -'payload symbols'. This tag then becomes the tagged stream key for the -payload chain. - - -\subsection packet_rx_hdr_chain Header Processing Chain - -The header processing chain is kicked off when the HPD block receives -the trigger stream tag (i.e., 'time_est'). We must first correct the -phase and fine frequency offset of the received samples. The -Correlation Estimator block will help us with this through the -'phase_est' tag. The \ref gr::digital::costas_loop_cc "Costas Loop" -looks for this tag, and, when found, it will take this estimate and -reset its own internal phase value, which greatly speed up -acquisition. The Costas loop will then track the phase and frequency -over the course of the header. - -With the constellation locked in time, phase, and frequency, we can -not decode the complex symbols. We use a \ref -gr::digital::constellation_soft_decoder_cf "Constellation Soft Decoder" -block for this, which uses the 'hdr_const' object to know the mappings -from complex space to bits. Specifically, it performs a soft decoding, -so the outputs are soft decision bits, which is useful for FEC -decoding that is performed next. - -The \ref gr::fec::decoder "FEC decoder" operates on the soft decisions -based on the hdr_dec object. Because of the bounded nature of the -header, we would expect simple block codes used here as well as a -fairly robust and easy to process code. In the current examples, we -only provide no code (via the \ref gr::fec::code::dummy_encoder -"Dummy Encoder" / \ref gr::fec::code::dummy_decoder "Dummy Decoder" -classes) or a repetition code (via the -\ref gr::fec::code::repetition_encoder "Repetition Encoder" / \ref -gr::fec::code::repetition_decoder "Repetition Decoder" classes). The -output of the FEC decoder block is a bit stream where each item is -either a 1 or a 0. - -The last step in the header processing stage is to parse that bit -stream back into the header. The \ref gr::digital::protocol_parser_b -"Packet Parser" block does this by receiving a bit stream, passing it -to the \ref gr::digital::header_format_base::parse "parse" function of -the packet formatter object, and emitting a message with the -information about the parsed data. - -The packet parsing is explained in detail in the \ref -gr::digital::header_format_base "Packet Formatter Base" class. The -parse function packs together the received bits into the different -header fields, checks that the header is correct, and the constructs a -PMT dictionary of the header information, such as the payload length -and other possible information like the type of constellation or FEC -coding used on the payload bits. This is the message that gets passed -back to the HPD block to guide the payload processing. - -If the packet formatter parsing operation fails by not getting enough -data or if the data is corrupted, it will return false. When the -Packet Parser sees this, it emits a message that just contains a \ref -page_pmt "PMT" False (pmt::PMT_F), which resets the HPD block to start -looking for another header trigger event. - -If the header parsing completes successfully, the HPD block gets a -message with information about the payload. Most importantly, it gets -information about how many symbols make up the payload. It then sends -a tagged stream to the payload processing chain with this many -symbols. - - -\subsection packet_rx_pld_chain Payload Processing Chain - -The payload processing chain behaves very similarly to the header -processing chain for the first few blocks. It starts by locking the -phase and frequency in another \ref gr::digital::costas_loop_cc -"Costas loop", and then perform \ref -gr::digital::constellation_soft_decoder_cf "soft decoding" on the -symbols using the 'pld_const' object. Because we come in as symbols -and out as soft decisions, the constellation soft decoder will produce -\ref gr::digital::constellation::bits_per_symbol() "bits_per_symbol()" -times as many outputs as inputs, but the soft decoder will not change -the tag stream information. To compensate for this, we use a \ref -gr::blocks::tagged_stream_multiply_length -"Tagged Stream Multiply Length" block to update the tagged stream tag -"payload symbols". We then move from the tagged stream mode into PDU -mode and perform the FEC decoding through the \ref -gr::fec::async_decoder "asynchronous FEC decoder". This decoder is -nice in that it comes in with soft bits and produces packed -bytes. These packed bytes are now the full payload with the CRC32 -appended. The \ref gr::digital::crc32_async_bb "Async CRC32" block in -"Check CRC" mode will take this PDU of packed bytes, calculate the CRC -and check it against the final four bytes of the payload. If they -match, the PDU is stripped of the CRC bytes and the frame is passed -out of the hier block. This PDU frame is now ready for use in higher -layers of processing. - -This takes us through the entire processing chain on the -receiver. From here, it is a matter of tweaking parameters and playing -with options and other setups to improve behavior. - -*/ |