summaryrefslogtreecommitdiff
path: root/docs/doxygen/other/ofdm.dox
blob: 9a3a18fab880d3273eeda0b2817a35c448a49f01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*! \page page_ofdm OFDM

\section ofdm_introduction Introduction

GNU Radio provides some blocks to transmit and receive OFDM-modulated signals.
In the following, we assume the reader is familiar with OFDM and how it works,
for an introduction to OFDM refer to standard textbooks on digital communication.

The blocks are designed in a very generic fashion. As a developer, this means that
often, a desired functionality can be achieved by correct parametrization of the
available blocks, but in some cases, custom blocks have to be included. The design
of the OFDM components is such that adding own functionality is possible with
very little friction.

\ref page_packet_data has an example of how to use OFDM in a packet-based
receiver.

\section ofdm_conventions Conventions and Notations

\subsection ofdm_fftshift FFT Shifting

In all cases where OFDM symbols are passed between blocks, the default behaviour
is to FFT-Shift these symbols, i.e. that the DC carrier is in the middle (to be
precise, it is on carrier \f$\lfloor N/2 \rfloor\f$ where N is the FFT length and
carrier indexing starts at 0).

The reason for this convention is that some blocks require FFT-shifted ordering
of the symbols to function (such as gr::digital::ofdm_chanest_vcvc), and for
consistency's sake, this was chosen as a default for all blocks that pass OFDM
symbols. Also, when viewing OFDM symbols, FFT-shifted symbols are in their
natural order, i.e. as they appear in the pass band.

\subsection ofdm_indexing Carrier Indexing

Carriers are always index starting at the DC carrier, which has the index 0
(you usually don't want to occupy this carrier). The carriers right of the
DC carrier (the ones at higher frequencies) are indexed with 1 through N/2-1
(N being the FFT length again).

The carriers left of the DC carrier (with lower frequencies) can be indexed
-N/2 through -1 or N/2 through N-1. Carrier indices N-1 and -1 are thus
equivalent. The advantage of using negative carrier indices is that the
FFT length can be changed without changing the carrier indexing.

\subsection ofdm_carrieralloc Carrier and Symbol Allocation

Many blocks require knowledge of which carriers are allocated, and whether they
carry data or pilot symbols. GNU Radio blocks uses three objects for this, typically
called \p occupied_carriers (for the data symbols), \p pilot_carriers and
\p pilot_symbols (for the pilot symbols).

Every one of these objects is a vector of vectors. \p occupied_carriers and
\p pilot_carriers identify the position within a frame where data and pilot
symbols are stored, respectively.

\p occupied_carriers[0] identifies which carriers are occupied on the first
OFDM symbol, \p occupied_carriers[1] does the same on the second OFDM symbol etc.

Here's an example:
\code
  occupied_carriers = ((-2, -1, 1, 3), (-3, -1, 1, 2))
  pilot_carriers = ((-3, 2), (-2, 3))
\endcode
Every OFDM symbol carries 4 data symbols. On the first OFDM symbol, they are on carriers -2, -1, 1 and 3.
Carriers -3 and 2 are not used, so they are where the pilot symbols can be placed.
On the second OFDM symbol, the occupied carriers are -3, -1, 1 and 2. The pilot
symbols must thus be placed elsewhere, and are put on carriers -2 and 3.

If there are more symbols in the OFDM frame than the length of \p occupied_carriers
or \p pilot_carriers, they wrap around (in this example, the third OFDM symbol
uses the allocation in \p occupied_carriers[0]).

But how are the pilot symbols set? This is a valid parametrization:
\code
  pilot_symbols = ((-1, 1j), (1, -1j), (-1, 1j), (-1j, 1))
\endcode

The position of these symbols are thos in \p pilot_carriers. So on the first OFDM
symbol, carrier -3 will transmit a -1, and carrier 2 will transmit a 1j.
Note that \p pilot_symbols is longer than \p pilot_carriers in this example--
this is valid, the symbols in \p pilot_symbols[2] will be mapped according
to \p pilot_carriers[0].

\section ofdm_detectsync Detection and Synchronisation

Before anything happens, an OFDM frame must be detected, the beginning of OFDM
symbols must be identified, and frequency offset must be estimated.

\section ofdm_tx Transmitting

\image html ofdm_tx_core.png "Core elements of an OFDM transmitter"

This image shows a very simple example of a transmitter. It is assumed that the
input is a stream of complex scalars with a length tag, i.e. the transmitter
will work on one frame at a time.

The first block is the carrier allocator (gr::digital::ofdm_carrier_allocator_cvc).
This sorts the incoming complex scalars onto OFDM carriers, and also places the
pilot symbols onto the correct positions.
There is also the option to pass OFDM symbols which are prepended in front of every
frame (i.e. preamble symbols). These can be used for detection, synchronisation
and channel estimation.

The carrier allocator outputs OFDM symbols (i.e. complex vectors of FFT length).
These must be converted to time domain signals before continuing, which is why
they are piped into an (I)FFT block. Note that because all the OFDM symbols are
treated in the shifted form, the IFFT block must be shifting as well.

Finally, the cyclic prefix is added to the OFDM symbols. The gr::digital::ofdm_cyclic_prefixer
can also perform pulse shaping on the OFDM symbols (raised cosine flanks in the
time domain).

\section ofdm_rx Receiving

On the receiver side, some more effort is necessary. The following flow graph
assumes that the input starts at the beginning of an OFDM frame and is prepended
with a Schmidl & Cox preamble for coarse frequency correction and channel
estimation. Also assumed is that the fine frequency offset is already corrected
and that the cyclic prefix has been removed. The latter can be achieved by a
gr::digital::header_payload_demux, the former can be done using a
gr::digital::ofdm_sync_sc_cc.

\image html ofdm_rx_core.png "Core elements of an OFDM receiver"

First, an FFT shifts the OFDM symbols into the frequency domain, where the signal
processing is performed (the OFDM frame is thus in the memory in matrix form).
It is passed to a block that uses the preambles to perform channel estimation
and coarse frequency offset. Both of these values are added to the output stream
as tags; the preambles are then removed from the stream and not propagated.

Note that this block does not correct the OFDM frame. Both the coarse frequency
offset correction and the equalizing (using the initial channel state estimate)
are done in the following block, gr::digital::ofdm_frame_equalizer_vcvc.
The interesting property about this block is that it uses a
gr::digital::ofdm_equalizer_base derived object to perform the actual equalization.

The last block in the frequency domain is the gr::digital::ofdm_serializer_vcc,
which is the inverse block to the carrier allocator.
It plucks the data symbols from the \p occupied_carriers and outputs them as a
stream of complex scalars. These can then be directly converted to bits, or passed
to a forward error correction decoder.

*/