working on sync_long
@ -158,9 +158,20 @@ texinfo_documents = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
# Example configuration for intersphinx: refer to the Python standard library.
|
||||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||||
|
|
||||||
|
# =============================================================
|
||||||
|
# Custom configurations
|
||||||
|
# =============================================================
|
||||||
|
#
|
||||||
|
# Enable figure numbering
|
||||||
numfig = True
|
numfig = True
|
||||||
|
|
||||||
|
# global macros
|
||||||
|
rst_prolog = """
|
||||||
|
.. |project| replace:: OpenOFDM
|
||||||
|
.. |us| replace:: :math:`\mu s`
|
||||||
|
"""
|
||||||
|
|
||||||
|
math_number_all = True
|
||||||
|
@ -12,7 +12,7 @@ for coarse frequency offset correction , which will be discussed separately in
|
|||||||
Power Trigger
|
Power Trigger
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
- **Module**: ``power_trigger.v``
|
- **Module**: :file:`power_trigger.v`
|
||||||
- **Input**: ``sample_in`` (16B I + 16B Q), ``sample_in_strobe`` (1B)
|
- **Input**: ``sample_in`` (16B I + 16B Q), ``sample_in_strobe`` (1B)
|
||||||
- **Output**: ``trigger`` (1B)
|
- **Output**: ``trigger`` (1B)
|
||||||
- **Setting Registers**: ``SR_POWER_THRES``, ``SR_POWER_WINDOW``,
|
- **Setting Registers**: ``SR_POWER_THRES``, ``SR_POWER_WINDOW``,
|
||||||
@ -24,7 +24,7 @@ we are trying to detect short preamble from "meaningful" signals. One example of
|
|||||||
"un-meaningful" signal is constant power levels, whose auto correlation metric
|
"un-meaningful" signal is constant power levels, whose auto correlation metric
|
||||||
is also very high (nearly 1) but obviously does not represent packet beginning.
|
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
|
The first module in the pipeline is the :file:`power_trigger.v`. It takes the I/Q
|
||||||
samples as input and asserts the ``trigger`` signal during a potential packet
|
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
|
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
|
samples before detecting a power trigger. This is useful to skip the spurious
|
||||||
@ -39,7 +39,7 @@ continuous samples.
|
|||||||
Short Preamble Detection
|
Short Preamble Detection
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
- **Module**: ``sync_short.v``
|
- **Module**: :file:`sync_short.v`
|
||||||
- **Input**: ``sample_in`` (16B I + 16B Q), ``sample_in_strobe`` (1B)
|
- **Input**: ``sample_in`` (16B I + 16B Q), ``sample_in_strobe`` (1B)
|
||||||
- **Output**: ``short_preamble_detected`` (1B)
|
- **Output**: ``short_preamble_detected`` (1B)
|
||||||
- **Setting Registers**: ``SR_MIN_PLATEAU``
|
- **Setting Registers**: ``SR_MIN_PLATEAU``
|
||||||
@ -74,6 +74,21 @@ preamble can be declared.
|
|||||||
|
|
||||||
Auto Correlation of the Short Preamble samples (N=48).
|
Auto Correlation of the Short Preamble samples (N=48).
|
||||||
|
|
||||||
|
To plot :numref:`fig_corr`, load the samples (see :ref:`sec_sample`), then:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
|
fig, ax = plt.subplots(nrows=2, ncols=1, sharex=True)
|
||||||
|
ax[0].plot([s.real for s in samples[:500]], '-bo')
|
||||||
|
ax[1].plot([abs(sum([samples[i+j]*samples[i+j+16].conjugate()
|
||||||
|
for j in range(0, 48)]))/
|
||||||
|
sum([abs(samples[i+j])**2 for j in range(0, 48)])
|
||||||
|
for i in range(0, 500)], '-ro')
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
:numref:`fig_corr` shows the auto correlation value of the samples in
|
: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
|
: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
|
during the short preamble period, but drops quickly after that. We can also see
|
||||||
|
BIN
docs/source/files/802.11-2012.pdf
Normal file
128
docs/source/files/lts.txt
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
-1.559999999999999998e-01
|
||||||
|
0.000000000000000000e+00
|
||||||
|
1.200000000000000025e-02
|
||||||
|
-9.800000000000000377e-02
|
||||||
|
9.199999999999999845e-02
|
||||||
|
-1.059999999999999970e-01
|
||||||
|
-9.199999999999999845e-02
|
||||||
|
-1.150000000000000050e-01
|
||||||
|
-3.000000000000000062e-03
|
||||||
|
-5.399999999999999939e-02
|
||||||
|
7.499999999999999722e-02
|
||||||
|
7.399999999999999634e-02
|
||||||
|
-1.270000000000000018e-01
|
||||||
|
2.100000000000000130e-02
|
||||||
|
-1.219999999999999973e-01
|
||||||
|
1.700000000000000122e-02
|
||||||
|
-3.500000000000000333e-02
|
||||||
|
1.509999999999999953e-01
|
||||||
|
-5.600000000000000117e-02
|
||||||
|
2.199999999999999872e-02
|
||||||
|
-5.999999999999999778e-02
|
||||||
|
-8.100000000000000255e-02
|
||||||
|
7.000000000000000666e-02
|
||||||
|
-1.400000000000000029e-02
|
||||||
|
8.200000000000000344e-02
|
||||||
|
-9.199999999999999845e-02
|
||||||
|
-1.310000000000000053e-01
|
||||||
|
-6.500000000000000222e-02
|
||||||
|
-5.700000000000000205e-02
|
||||||
|
-3.899999999999999994e-02
|
||||||
|
3.699999999999999817e-02
|
||||||
|
-9.800000000000000377e-02
|
||||||
|
6.199999999999999956e-02
|
||||||
|
6.199999999999999956e-02
|
||||||
|
1.189999999999999947e-01
|
||||||
|
4.000000000000000083e-03
|
||||||
|
-2.199999999999999872e-02
|
||||||
|
-1.610000000000000042e-01
|
||||||
|
5.899999999999999689e-02
|
||||||
|
1.499999999999999944e-02
|
||||||
|
2.400000000000000050e-02
|
||||||
|
5.899999999999999689e-02
|
||||||
|
-1.370000000000000107e-01
|
||||||
|
4.700000000000000011e-02
|
||||||
|
1.000000000000000021e-03
|
||||||
|
1.150000000000000050e-01
|
||||||
|
5.299999999999999850e-02
|
||||||
|
-4.000000000000000083e-03
|
||||||
|
9.800000000000000377e-02
|
||||||
|
2.599999999999999881e-02
|
||||||
|
-3.799999999999999906e-02
|
||||||
|
1.059999999999999970e-01
|
||||||
|
-1.150000000000000050e-01
|
||||||
|
5.500000000000000028e-02
|
||||||
|
5.999999999999999778e-02
|
||||||
|
8.799999999999999489e-02
|
||||||
|
2.100000000000000130e-02
|
||||||
|
-2.800000000000000058e-02
|
||||||
|
9.700000000000000289e-02
|
||||||
|
-8.300000000000000433e-02
|
||||||
|
4.000000000000000083e-02
|
||||||
|
1.110000000000000014e-01
|
||||||
|
-5.000000000000000104e-03
|
||||||
|
1.199999999999999956e-01
|
||||||
|
1.559999999999999998e-01
|
||||||
|
0.000000000000000000e+00
|
||||||
|
-5.000000000000000104e-03
|
||||||
|
-1.199999999999999956e-01
|
||||||
|
4.000000000000000083e-02
|
||||||
|
-1.110000000000000014e-01
|
||||||
|
9.700000000000000289e-02
|
||||||
|
8.300000000000000433e-02
|
||||||
|
2.100000000000000130e-02
|
||||||
|
2.800000000000000058e-02
|
||||||
|
5.999999999999999778e-02
|
||||||
|
-8.799999999999999489e-02
|
||||||
|
-1.150000000000000050e-01
|
||||||
|
-5.500000000000000028e-02
|
||||||
|
-3.799999999999999906e-02
|
||||||
|
-1.059999999999999970e-01
|
||||||
|
9.800000000000000377e-02
|
||||||
|
-2.599999999999999881e-02
|
||||||
|
5.299999999999999850e-02
|
||||||
|
4.000000000000000083e-03
|
||||||
|
1.000000000000000021e-03
|
||||||
|
-1.150000000000000050e-01
|
||||||
|
-1.370000000000000107e-01
|
||||||
|
-4.700000000000000011e-02
|
||||||
|
2.400000000000000050e-02
|
||||||
|
-5.899999999999999689e-02
|
||||||
|
5.899999999999999689e-02
|
||||||
|
-1.499999999999999944e-02
|
||||||
|
-2.199999999999999872e-02
|
||||||
|
1.610000000000000042e-01
|
||||||
|
1.189999999999999947e-01
|
||||||
|
-4.000000000000000083e-03
|
||||||
|
6.199999999999999956e-02
|
||||||
|
-6.199999999999999956e-02
|
||||||
|
3.699999999999999817e-02
|
||||||
|
9.800000000000000377e-02
|
||||||
|
-5.700000000000000205e-02
|
||||||
|
3.899999999999999994e-02
|
||||||
|
-1.310000000000000053e-01
|
||||||
|
6.500000000000000222e-02
|
||||||
|
8.200000000000000344e-02
|
||||||
|
9.199999999999999845e-02
|
||||||
|
7.000000000000000666e-02
|
||||||
|
1.400000000000000029e-02
|
||||||
|
-5.999999999999999778e-02
|
||||||
|
8.100000000000000255e-02
|
||||||
|
-5.600000000000000117e-02
|
||||||
|
-2.199999999999999872e-02
|
||||||
|
-3.500000000000000333e-02
|
||||||
|
-1.509999999999999953e-01
|
||||||
|
-1.219999999999999973e-01
|
||||||
|
-1.700000000000000122e-02
|
||||||
|
-1.270000000000000018e-01
|
||||||
|
-2.100000000000000130e-02
|
||||||
|
7.499999999999999722e-02
|
||||||
|
-7.399999999999999634e-02
|
||||||
|
-3.000000000000000062e-03
|
||||||
|
5.399999999999999939e-02
|
||||||
|
-9.199999999999999845e-02
|
||||||
|
1.150000000000000050e-01
|
||||||
|
9.199999999999999845e-02
|
||||||
|
1.059999999999999970e-01
|
||||||
|
1.200000000000000025e-02
|
||||||
|
9.800000000000000377e-02
|
BIN
docs/source/files/samples.dat
Normal file
@ -3,14 +3,14 @@
|
|||||||
Frequency Offset Correction
|
Frequency Offset Correction
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
This paper [1]_ explains why frequency offset occurs and how to correct it. In a
|
:download:`This paper </files/vtc04_freq_offset.pdf>` [1]_ explains why
|
||||||
nutshell, there are two types of frequency offsets. The first is called
|
frequency offset occurs and how to correct it. In a nutshell, there are two
|
||||||
**Carrier Frequency Offset (CFO)** and is caused by the difference between the
|
types of frequency offsets. The first is called **Carrier Frequency Offset
|
||||||
transmitter and receiver's Local Oscillator (LO). This symptom of this offset is
|
(CFO)** and is caused by the difference between the transmitter and receiver's
|
||||||
a phase rotation of incoming I/Q samples (time domain). The second is **Sampling
|
Local Oscillator (LO). This symptom of this offset is a phase rotation of
|
||||||
Frequency Offset (SFO)** and is caused by the sampling effect. The symptom of
|
incoming I/Q samples (time domain). The second is **Sampling Frequency Offset
|
||||||
this offset is a phase rotation of constellation points after FFT (frequency
|
(SFO)** and is caused by the sampling effect. The symptom of this offset is a
|
||||||
domain).
|
phase rotation of constellation points after FFT (frequency domain).
|
||||||
|
|
||||||
The CFO can be corrected with the help of short preamble (Coarse) long preamble
|
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
|
(Fine). And the SFO can be corrected using the pilot sub-carriers in each OFDM
|
||||||
@ -64,10 +64,10 @@ long preamble) are corrected as:
|
|||||||
|
|
||||||
S'[m] = S[m]e^{-jm\alpha_{ST}}, m = 0, 1, 2, \ldots
|
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
|
In |project|, 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
|
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.
|
``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.
|
.. [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.
|
||||||
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 72 KiB |
BIN
docs/source/images/lts.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
docs/source/images/match_size.png
Normal file
After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 80 KiB |
BIN
docs/source/images/training.png
Normal file
After Width: | Height: | Size: 42 KiB |
@ -3,15 +3,17 @@
|
|||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
Welcome to OpenOFDM's documentation!
|
Welcome to |project|'s documentation!
|
||||||
====================================
|
=====================================
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
:caption: Contents:
|
:caption: Contents:
|
||||||
|
|
||||||
|
sample
|
||||||
detection
|
detection
|
||||||
freq_offset
|
freq_offset
|
||||||
|
sync_long
|
||||||
setting
|
setting
|
||||||
verilog
|
verilog
|
||||||
|
|
||||||
|
19
docs/source/sample.rst
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
.. _sec_sample:
|
||||||
|
|
||||||
|
Sample File
|
||||||
|
===========
|
||||||
|
|
||||||
|
Throughout this documentation we will be using a sample file that contains the
|
||||||
|
I/Q samples of a 802.11a packet at 24 Mbps (16-QAM). It'll be helpful to use a
|
||||||
|
interactive iPython session and exercise various steps discussed in the
|
||||||
|
document.
|
||||||
|
|
||||||
|
Download the sample file from :download:`here </files/samples.dat>`, the data
|
||||||
|
can be loaded as follows:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import scipy
|
||||||
|
|
||||||
|
wave = scipy.fromfile('samples.dat', dtype=scipy.int16)
|
||||||
|
samples = [complex(i, q) for i, q in zip(wave[::2], wave[1::2])]
|
@ -6,7 +6,7 @@ Setting Registers
|
|||||||
- **Output**: ``out``, ``changed``
|
- **Output**: ``out``, ``changed``
|
||||||
|
|
||||||
To enable dynamic configuration of decoding parameters at runtime, the USRP N210
|
To enable dynamic configuration of decoding parameters at runtime, the USRP N210
|
||||||
provides the setting register mechanism. Most modules in OpenOFDM have three
|
provides the setting register mechanism. Most modules in |project| have three
|
||||||
common inputs for such purpose:
|
common inputs for such purpose:
|
||||||
|
|
||||||
- ``set_stb (1)``: asserts high when the setting data is valid
|
- ``set_stb (1)``: asserts high when the setting data is valid
|
||||||
@ -14,9 +14,9 @@ common inputs for such purpose:
|
|||||||
- ``set_data (32)``: the register value
|
- ``set_data (32)``: the register value
|
||||||
|
|
||||||
|
|
||||||
Here is a list of setting registers in OpenOFDM.
|
Here is a list of setting registers in |project|.
|
||||||
|
|
||||||
.. table:: List of Setting Registers in OpenOFDM.
|
.. table:: List of Setting Registers in |project|.
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+
|
+-----------------+------+-----------------+-----------+---------------+---------------------------------------------------------------+
|
||||||
|
101
docs/source/sync_long.rst
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
Symbol Alignment
|
||||||
|
================
|
||||||
|
|
||||||
|
After detecting the packet, the next step is to determine precisely where each
|
||||||
|
OFDM symbol starts. In 802.11, each OFDM symbol is 4 |us| long. At 20 MSPS
|
||||||
|
sampling rate, this means each OFDM symbol contains 80 samples. The task is to
|
||||||
|
group the incoming streaming of samples into 80-sample OFDM symbols. This can be
|
||||||
|
achieved using the long preamble following the short preamble.
|
||||||
|
|
||||||
|
.. _fig_training:
|
||||||
|
.. figure:: /images/training.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
802.11 OFDM Packet Structure (Fig 18-4 in 802.11-2012 Std)
|
||||||
|
|
||||||
|
As shown in :numref:`fig_training`, the long preamble duration is 8 |us| (160
|
||||||
|
samples), and contains two identical long training sequence (LTS), 64 samples each.
|
||||||
|
The LTS is known and we can use `matched filter
|
||||||
|
<https://en.wikipedia.org/wiki/Matched_filter>`_ to find it.
|
||||||
|
|
||||||
|
The match *score* at sample :math:`i` can be calculated as follows.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
:label: eq_matched
|
||||||
|
|
||||||
|
Y[i] = \sum_{k=0}^{63}(S[i+k]\overline{H[63-k]})
|
||||||
|
|
||||||
|
where :math:`H` is the 64 sample known LTS in time domain, and can be found in
|
||||||
|
Table L-6 in :download:`802.11-2012 std </files/802.11-2012.pdf>` (index 64 to
|
||||||
|
127). A numpy readable file of the LTS (64 samples) can be found :download:`here
|
||||||
|
</files/lts.txt>`, and can be read like this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> lts = np.loadtxt('lts.txt').view(complex)
|
||||||
|
|
||||||
|
.. _fig_lts:
|
||||||
|
.. figure:: /images/lts.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Long Preamble and Matched Filter Result
|
||||||
|
|
||||||
|
To plot :numref:`fig_lts`, load the data file (see :ref:`sec_sample`), then:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# in scripts/decode.py
|
||||||
|
import decode
|
||||||
|
import numpy as np
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
|
fig, ax = plt.subplots(nrows=2, ncols=1, sharex=True)
|
||||||
|
ax[0].plot([c.real for c in samples][:500])
|
||||||
|
# lts is from the above code snippet
|
||||||
|
ax[1].plot([abs(c) for c in np.convolve(samples, lts, mode='same')][:500], '-ro')
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:numref:`fig_lts` shows the long preamble samples and also the result of matched
|
||||||
|
filter. We can clearly see two spikes corresponding the two LTS in long
|
||||||
|
preamble. And the spike width is only 1 sample which shows exactly the beginning
|
||||||
|
of each sequence. Suppose the sample index if the first spike is :math:`N`, then
|
||||||
|
the 160 sample long preamble starts at sample :math:`N-33`.
|
||||||
|
|
||||||
|
This all seems nice and dandy, but as it comes to Verilog implementation, we
|
||||||
|
have to make a few compromises.
|
||||||
|
|
||||||
|
First, from :eq:`eq_matched` we can see for each sample, we need to perform 64
|
||||||
|
complex number multiplications, which would consume a lot FPGA resources.
|
||||||
|
Therefore, we need to reduce the matched filter size. The idea is to only use
|
||||||
|
a portion instead of all the LTS samples.
|
||||||
|
|
||||||
|
.. _fig_match_size:
|
||||||
|
.. figure:: /images/match_size.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Matched Filter with Various Size (8, 16, 32, 64)
|
||||||
|
|
||||||
|
:numref:`fig_match_size` can be plotted as:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
lp = decode.LONG_PREAMBLE
|
||||||
|
|
||||||
|
fig, ax = plt.subplots(nrows=5, ncols=1, sharex=True)
|
||||||
|
ax[0].plot([c.real for c in lp])
|
||||||
|
ax[1].plot([abs(c) for c in np.convolve(lp, lts[:8], mode='same')], '-ro')
|
||||||
|
ax[2].plot([abs(c) for c in np.convolve(lp, lts[:16], mode='same')], '-ro')
|
||||||
|
ax[3].plot([abs(c) for c in np.convolve(lp, lts[:32], mode='same')], '-ro');
|
||||||
|
ax[4].plot([abs(c) for c in np.convolve(lp, lts, mode='same')], '-ro')
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
:numref:`fig_match_size` shows the long preamble (160 samples) as well as
|
||||||
|
matched filter with different size. It can be seen that using the first 16
|
||||||
|
samples of LTS is good enough to exhibit two narrow spikes. Therefore, |project|
|
||||||
|
use matched filter of size 16 for symbol alignment. And the first sample of the
|
||||||
|
long preamble starts at :math:`N_{16}-57`, where :math:`N_{16}` is the index of the
|
||||||
|
first spike when the filter size is 16 (:math:`N_{32}-49` when filter size is
|
||||||
|
32).
|
@ -3,13 +3,13 @@ Verilog Hacks
|
|||||||
|
|
||||||
Because of the limited capability of FPGA computation, compromises often need to
|
Because of the limited capability of FPGA computation, compromises often need to
|
||||||
made in the actual Verilog implementation. The most used techniques include
|
made in the actual Verilog implementation. The most used techniques include
|
||||||
quantization and look up table. In OpenOFDM, these approximations are used.
|
quantization and look up table. In |project|, these approximations are used.
|
||||||
|
|
||||||
|
|
||||||
Magnitude Estimation
|
Magnitude Estimation
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
**Module**: ``complex_to_mag.v``
|
**Module**: :file:`complex_to_mag.v`
|
||||||
|
|
||||||
In the ``sync_short`` module, we need to calculate the magnitude of the
|
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
|
``prod_avg``, whose real and imagine part are both 32-bits. To avoid 32-bit
|
||||||
@ -39,11 +39,11 @@ magnitude is calculated.
|
|||||||
Phase Estimation
|
Phase Estimation
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
**Module**:: ``phase.v``
|
**Module**:: :file:`phase.v`
|
||||||
|
|
||||||
When correcting the frequency offset, we need to estimate the phase of a complex
|
When correcting the frequency offset, we need to estimate the phase of a complex
|
||||||
number. The *right* way of doing this is probably using the `CORDIC
|
number. The *right* way of doing this is probably using the `CORDIC
|
||||||
<https://dspguru.com/dsp/faqs/cordic/>`_ algorithm. In OpenOFDM, we use look up
|
<https://dspguru.com/dsp/faqs/cordic/>`_ algorithm. In |project|, we use look up
|
||||||
table.
|
table.
|
||||||
|
|
||||||
More specifically, we calculate the phase using the :math:`arctan` function.
|
More specifically, we calculate the phase using the :math:`arctan` function.
|
||||||
@ -91,9 +91,9 @@ This :math:`arctan` look up table is generated using the
|
|||||||
|
|
||||||
|
|
||||||
Note that we also scale up the :math:`arctan` values to distinguish adjacent
|
Note that we also scale up the :math:`arctan` values to distinguish adjacent
|
||||||
values. This also systematically scale up :math:`\pi` in OpenOFDM. In fact,
|
values. This also systematically scale up :math:`\pi` in |project|. In fact,
|
||||||
:math:`\pi` is defined as :math:`1608=int(\pi*512)` in
|
:math:`\pi` is defined as :math:`1608=int(\pi*512)` in
|
||||||
``verilog/common_params.v``.
|
:file:`verilog/common_params.v`.
|
||||||
|
|
||||||
The generated lookup table is stored in the ``verilog/atan_lut.coe``
|
The generated lookup table is stored in the ``verilog/atan_lut.coe``
|
||||||
file (see `COE File Syntax
|
file (see `COE File Syntax
|
||||||
@ -101,4 +101,4 @@ file (see `COE File Syntax
|
|||||||
Refer to `this guide
|
Refer to `this guide
|
||||||
<https://www.xilinx.com/itp/xilinx10/isehelp/cgn_p_memed_single_block.htm>`_ on
|
<https://www.xilinx.com/itp/xilinx10/isehelp/cgn_p_memed_single_block.htm>`_ on
|
||||||
how to create a look up table in Xilinx ISE. The generated module is stored in
|
how to create a look up table in Xilinx ISE. The generated module is stored in
|
||||||
``verilog/coregen/atan_lut.v``.
|
:file:`verilog/coregen/atan_lut.v`.
|
||||||
|