diff --git a/docs/source/verilog.rst b/docs/source/verilog.rst
index 759488d..5a32d78 100644
--- a/docs/source/verilog.rst
+++ b/docs/source/verilog.rst
@@ -42,34 +42,63 @@ 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.
+number. The *right* way of doing this is probably using the `CORDIC
+`_ algorithm. In OpenOFDM, we use look up
+table.
+
+More specifically, we calculate the phase using the :math:`arctan` function.
.. math::
- \angle(\langle I, Q\rangle) = arctan(\frac{Q}{I})
+ \theta = \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.
+1. Project the complex number to the :math:`[0, \pi/4]` range, so that the
+ :math:`tan(\theta)` range is :math:`[0, 1]`.
#. 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:
+Step 1 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
-`_ algorithm. However, this function is
-implemented using look up tables in OpenOFDM.
+In the lookup table used in step 3, we use :math:`int(tan(\theta)*256)` as the
+key, which effectively maps 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.
-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.
+This :math:`arctan` look up table is generated using the
+``scripts/gen_atan_lut.py`` script. The core logic is as follows:
+
+.. code-block:: python
+ :linenos:
+
+ SIZE = 2**8
+ SCALE = SIZE*2
+ data = []
+ for i in range(SIZE):
+ key = float(i)/SIZE
+ val = int(round(math.atan(key)*SCALE))
+ data.append(val)
+
+
+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,
+:math:`\pi` is defined as :math:`1608=int(\pi*512)` in
+``verilog/common_params.v``.
+
+The generated lookup table is stored in the ``verilog/atan_lut.coe``
+file (see `COE File Syntax
+`_).
+Refer to `this guide
+`_ on
+how to create a look up table in Xilinx ISE. The generated module is stored in
+``verilog/coregen/atan_lut.v``.
diff --git a/scripts/decode.py b/scripts/decode.py
index 28a98dc..4a1860c 100644
--- a/scripts/decode.py
+++ b/scripts/decode.py
@@ -225,6 +225,7 @@ class ChannelEstimator(object):
prod_sum += prod
beta = cmath.phase(prod_sum)
print "[PILOT OFFSET] %f (%d)" % (beta, int(beta*PHASE_SCALE))
+ # beta = 0
carriers = []
for c in self.subcarriers:
if c in PILOT_SUBCARRIES:
@@ -269,8 +270,8 @@ class ChannelEstimator(object):
coarse_offset = cmath.phase(sum([sts[i]*sts[i+16].conjugate()
for i in range(len(sts)-16)]))/16
- coarse_offset = int(coarse_offset*256)/256.0
print '[COARSE OFFSET] %f (%d)' % (coarse_offset, int(coarse_offset*PHASE_SCALE))
+ # coarse_offset = 0
# coarse correction
lts = [c*cmath.exp(complex(0, n*coarse_offset))
@@ -279,7 +280,7 @@ class ChannelEstimator(object):
fine_offset = cmath.phase(sum([lts[i]*lts[i+64].conjugate()
for i in range(len(lts)-64)]))/64
print '[FINE OFFSET] %f (%d)' % (fine_offset, int(fine_offset*PHASE_SCALE))
- fine_offset = 0
+ # fine_offset = 0
self.lts_samples = [c*cmath.exp(complex(0, n*fine_offset))
for n, c in enumerate(lts)]
@@ -430,6 +431,7 @@ class Decoder(object):
def decode_next(self, *args, **kwargs):
trigger = False
samples = []
+ glbl_index = 0
while True:
chunk = array.array('h', self.fh.read(self.window))
chunk = [complex(i, q) for i, q in zip(chunk[::2], chunk[1::2])]
@@ -437,6 +439,7 @@ class Decoder(object):
trigger = True
samples = []
print "Power trigger at %d" % (self.count)
+ glbl_index = self.count
self.count += self.window
@@ -448,6 +451,8 @@ class Decoder(object):
if start is None:
trigger = False
else:
+ print "Decoding packet starting from sample %d" %\
+ (glbl_index + start)
return self.decode(samples[start:], *args, **kwargs)
def find_pkt(self, samples):