This commit is contained in:
Jinghao Shi 2017-04-05 16:06:23 -04:00
parent 63dd5a42f2
commit 28c57fc17f
17 changed files with 288 additions and 29 deletions

View File

@ -162,3 +162,5 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}
numfig = True

107
docs/source/detection.rst Normal file
View File

@ -0,0 +1,107 @@
Packet Detection
================
802.11 OFDM packets start with a short PLCP Preamble sequence to help the
receiver detect the beginning of the packet. The short preamble duration is
8 us. At 20 MSPS sampling rate, it contains 10 repeating sequence of 16 I/Q
samples, or 160 samples in total. The short preamble also helps the receiver
for coarse frequency offset correction , which will be discussed separately in
:ref:`freq_offset`.
Power Trigger
-------------
- **Module**: ``power_trigger.v``
- **Input**: ``sample_in`` (16B I + 16B Q), ``sample_in_strobe`` (1B)
- **Output**: ``trigger`` (1B)
- **Setting Registers**: ``SR_POWER_THRES``, ``SR_POWER_WINDOW``,
``SR_SKIP_SAMPLE``.
The core idea of detecting the short preamble is to utilize its repeating nature
by calculating the auto correlation metric. But before that, we need to make sure
we are trying to detect short preamble from "meaningful" signals. One example of
"un-meaningful" signal is constant power levels, whose auto correlation metric
is also very high (nearly 1) but obviously does not represent packet beginning.
The first module in the pipeline is the ``power_trigger.v``. It takes the I/Q
samples as input and asserts the ``trigger`` signal during a potential packet
activity. Optionally, it can be configured to skip the first certain number of
samples before detecting a power trigger. This is useful to skip the spurious
signals during the intimal hardware stabilization phase.
The logic of the ``power_trigger`` module is quite simple: after skipping
certain number of initial samples, it waits for significant power increase and
triggers the ``trigger`` signal upon detection. The ``trigger`` signal is
asserted until the power level is smaller than a threshold for certain number of
continuous samples.
Short Preamble Detection
------------------------
- **Module**: ``sync_short.v``
- **Input**: ``sample_in`` (16B I + 16B Q), ``sample_in_strobe`` (1B)
- **Output**: ``short_preamble_detected`` (1B)
- **Setting Registers**: ``SR_MIN_PLATEAU``
.. _fig_short_preamble:
.. figure:: /images/short_preamble.png
:align: center
In-Phase of Short Preamble.
:numref:`fig_short_preamble` shows the in-phase of the beginning of a packet.
Some repeating patterns can clearly be seen. We can utilize this characteristic
and calculate the auto correlation metric of incoming signals to detect such
pattern:
.. math::
corr[i] = \frac{\left\lVert\sum_{i=0}^{N}{S[i]*\overline{S[i+16]}}\right\rVert}
{\sum_{i=0}^{N}{S[i]*\overline{S[i]}}}
where :math:`S[i]` is the :math:`\langle I,Q \rangle` sample expressed as a
complex number, and :math:`\overline{S[i]}` is its conjugate, :math:`N` is the
correlation window size. The correlation
reaches 1 if the incoming signal is repeating itself every 16 samples. If the
correlation stays high for certain number of continuous samples, then a short
preamble can be declared.
.. _fig_corr:
.. figure:: /images/corr.png
:align: center
Auto Correlation of the Short Preamble samples (N=48).
:numref:`fig_corr` shows the auto correlation value of the samples in
:numref:`fig_short_preamble`. We can see that the correlation value is almost 1
during the short preamble period, but drops quickly after that. We can also see
that for the very first 20 samples or so, the correlation value is also very
high. This is because the silence also repeats itself (at arbitrary interval)!
That's why we first use the ``power_trigger`` module to detect actual packet
activity and only perform short preamble detection on non-silent samples.
A straight forward implementation would require
both multiplication and division. However, on FPGAs devision consumes a lot of
resources so we really want to avoid it. In current implementation, we use a
fixed threshold (0.75) for the correlation so that we can use bit-shift to
achieve the purpose. In particular, we calculate ``numerator>>1 + numerator>>2``
and compare that with the denominator. For the correlation window size, we set
:math:`N=16`.
.. _fig_sync_short:
.. figure:: /images/sync_short.png
:align: center
``sync_short`` Module Diagram
:numref:`fig_sync_short` shows the internal module diagram of the ``sync_short``
module. In addition to the number of consecutive samples with correlation
larger than 0.75, the ``sync_short`` module also checks if the incoming signal
has both positive (> 25%) and negative (> 25%) samples to further eliminate
false positives (e.g., when the incoming signals are constant non-zero values).
Again, the thresholds (25%) are chosen so that we can use only bit-shifts for
the calculation.

Binary file not shown.

View File

@ -2,3 +2,72 @@
Frequency Offset Correction
===========================
This paper [1]_ explains why frequency offset occurs and how to correct it. In a
nutshell, there are two types of frequency offsets. The first is called
**Carrier Frequency Offset (CFO)** and is caused by the difference between the
transmitter and receiver's Local Oscillator (LO). This symptom of this offset is
a phase rotation of incoming I/Q samples (time domain). The second is **Sampling
Frequency Offset (SFO)** and is caused by the sampling effect. The symptom of
this offset is a phase rotation of constellation points after FFT (frequency
domain).
The CFO can be corrected with the help of short preamble (Coarse) long preamble
(Fine). And the SFO can be corrected using the pilot sub-carriers in each OFDM
symbol. Before we get into how exactly the correction is done. Let's see
visually how each correction step helps in the final constellation plane.
.. _fig_cons:
.. figure:: /images/cons.png
:align: center
Constellation Points Without Any Correction
.. figure:: /images/cons_w_coarse.png
:align: center
Constellation Points With Only Coarse Correction
.. figure:: /images/cons_w_coarse_fine.png
:align: center
Constellation Points With both Coarse and Fine Correction
.. _fig_cons_full:
.. figure:: /images/cons_w_coarse_fine_pilot.png
:align: center
Constellation Points With Coarse, Fine and Pilot Correction
:numref:`fig_cons` to :numref:`fig_cons_full` shows the constellation points of
a 64-QAM modulated 802.11a packet.
Coarse CFO Correction
---------------------
The coarse CFO can be estimated using the short preamble as follows:
.. math::
\alpha_{ST} = \frac{1}{16}\angle(\sum_{i=0}^{N}\overline{S[i]}S[i+16])
where :math:`\angle(\cdot)` is the phase of complex number and :math:`N \le 144
(160 - 16)` is the subset of short preambles utilized. The intuition is that the
phase difference between S[i] and S[i+16] represents the accumulated CFO over 16
samples.
After getting :math:`\alpha_{ST}`, each following I/Q samples (starting from
long preamble) are corrected as:
.. math::
S'[m] = S[m]e^{-jm\alpha_{ST}}, m = 0, 1, 2, \ldots
In OpenOFDM, the coarse CFO is calculated in the ``sync_short`` module, and we
set :math:`N=64`. The ``prod_avg`` in :numref:`fig_sync_short` is fed into a
``moving_avg`` module with window size set to 64.
.. [1] Sourour, Essam, Hussein El-Ghoroury, and Dale McNeill. "Frequency Offset Estimation and Correction in the IEEE 802.11 a WLAN." Vehicular Technology Conference, 2004. VTC2004-Fall. 2004 IEEE 60th. Vol. 7. IEEE, 2004.

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/source/images/cons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/source/images/corr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -10,8 +10,10 @@ Welcome to OpenOFDM's documentation!
:maxdepth: 2
:caption: Contents:
power
detection
freq_offset
setting
verilog

View File

@ -1,28 +0,0 @@
Packet Detection
================
802.11 OFDM packets start with a short PLCP Preamble sequence to help the
receiver detect the beginning of the packet. The short preamble duration is
8 us. At 20 MSPS sampling rate, it contains 10 repeating sequence of 16 I/Q
samples. The short preamble also helps the receiver for coarse frequency offset
correction , which will be discussed separately in :ref:`freq_offset`.
The core idea of detecting the short preamble is to utilize its repeating nature
by calculating the auto correlation metric. But before that, we need to make sure
we are trying to detect short preamble from "meaningful" signals. One example of
"un-meaningful" signal is constant power levels, whose auto correlation metric
is very high but does not represent packet beginning.
Power Trigger
-------------
- **Module**: ``power_trigger.v``
- **Input**: ``sample_in`` (16B I + 16B Q), ``sample_in_strobe`` (1B)
- **Output**: ``trigger`` (1B)
The first module in the pipeline is the ``power_trigger.v``. It takes the I/Q
samples as input and asserts the ``trigger`` signal during a potential packet
activity. Optionally, it can be configured to skip the first certain number of
samples before detecting a power trigger. This is useful to skip the spurious
signals during the intimal hardware stabilization phase.

32
docs/source/setting.rst Normal file
View File

@ -0,0 +1,32 @@
Setting Registers
=================
- **Module**: ``usrp/setting_reg.v``
- **Input**: ``set_stb``, ``set_addr`` and ``set_data``
- **Output**: ``out``, ``changed``
To enable dynamic configuration of decoding parameters at runtime, the USRP N210
provides the setting register mechanism. Most modules in OpenOFDM have three
common inputs for such purpose:
- ``set_stb (1)``: asserts high when the setting data is valid
- ``set_addr (8)``: register address (256 registers possible in total)
- ``set_data (32)``: the register value
Here is a list of setting registers in OpenOFDM.
.. table:: List of Setting Registers in OpenOFDM.
:align: center
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+
| Name | Addr | Module | Bit Width | Default Value | Description |
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+
| SR_POWRE_THRES | 3 | power_trigger.v | 16 | 100 | Threshold for power trigger |
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+
| SR_POWER_WINDOW | 4 | power_trigger.v | 16 | 80 | Number of samples to wait before reset the trigger signal |
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+
| SR_SKIP_SAMPLE | 5 | power_trigger.v | 32 | 5000000 | Number of samples to skip initially |
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+
| SR_MIN_PLATEAU | 6 | sync_short.v | 32 | 100 | Minimum number of plateau samples to declare a short preamble |
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+

75
docs/source/verilog.rst Normal file
View File

@ -0,0 +1,75 @@
Verilog Hacks
=============
Because of the limited capability of FPGA computation, compromises often need to
made in the actual Verilog implementation. The most used techniques include
quantization and look up table. In OpenOFDM, these approximations are used.
Magnitude Estimation
--------------------
**Module**: ``complex_to_mag.v``
In the ``sync_short`` module, we need to calculate the magnitude of the
``prod_avg``, whose real and imagine part are both 32-bits. To avoid 32-bit
multiplication, we use the `Magnitude Estimator Trick from DSP Guru
<https://dspguru.com/dsp/tricks/magnitude-estimator/>`_. In particular, the
magnitude of complex number :math:`\langle I, Q\rangle` is estimated as:
.. math::
M \approx \alpha*max(|I|, |Q|) + \beta*min(|I|, |Q|)
And we set :math:`\alpha = 1` and :math:`\beta = 0.25` so that only simple
bit-shift is needed.
.. _fig_complex_to_mag_wave:
.. figure:: /images/complex_to_mag_wave.png
:align: center
Waveform of ``complex_to_mag`` Module
:numref:`fig_complex_to_mag_wave` shows the waveform of the ``complex_to_mag``
module. In the first clock cycle, we calculate ``abs_i`` and ``abs_q``. In the
second cycle, ``max`` and ``min`` are determined. In the final cycle, the
magnitude is calculated.
Phase Estimation
----------------
**Module**:: ``phase.v``
When correcting the frequency offset, we need to estimate the phase of a complex
number, which can be calculated using the :math:`arctan` function.
.. math::
\angle(\langle I, Q\rangle) = arctan(\frac{Q}{I})
The overall steps are:
1. Project the complex number to the :math:`[0, \pi/4]` range.
#. Calculate :math:`arctan` (division required)
#. Looking up the quantized :math:`arctan` table
#. Project the phase back to the :math:`[-\pi, \pi)` range
Here we use both quantization and look up table techniques.
The first step can be achieved by this transformation:
.. math::
\langle I, Q\rangle \rightarrow \langle max(|I|, |Q|), min(|I|, |Q|)\rangle
The *right* way to calculate :math:`arctan` is probably using the `CORDIC
<https://dspguru.com/dsp/faqs/cordic/>`_ algorithm. However, this function is
implemented using look up tables in OpenOFDM.
In the table, we use :math:`int(tan(\angle)*256)` as the key, which effective
map the :math:`[0.0, 1.0]` range of :math:`tan` function to the integer range of
:math:`[0, 256]`. In other words, we quantize the :math:`[0, \pi/4]` quadrant
into 256 slices.