fun_ofdm  1.0
802.11a Physical Layer for USRP
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Macros Pages
timing_sync.cpp
Go to the documentation of this file.
1 
10 #include "timing_sync.h"
11 
12 #include <algorithm>
13 #include <cstring>
14 #include <iostream>
15 
16 #include "preamble.h"
17 
18 namespace fun
19 {
27  block("timing_sync"),
28  m_phase_acc(0),
29  m_phase_offset(0),
30  m_carryover(CARRYOVER_LENGTH, tagged_sample())
31  {}
32 
33  int lts_count = 0;
34 
52  {
53 
54  if(input_buffer.size() == 0) return;
55  assert(input_buffer.size() > CARRYOVER_LENGTH);
56  output_buffer.resize(input_buffer.size());
57 
58  std::vector<tagged_sample> input(input_buffer.size() + CARRYOVER_LENGTH);
59 
60  memcpy(&input[0],
61  &m_carryover[0],
63 
64  memcpy(&input[CARRYOVER_LENGTH],
65  &input_buffer[0],
66  input_buffer.size() * sizeof(tagged_sample));
67 
68  for(int x = 0; x < input.size() - CARRYOVER_LENGTH; x++)
69  {
70  // End of STS found: Look for LTS peaks
71  if(input[x].tag == STS_END)
72  {
73  // Cross correlate against the LTS
74  std::vector<std::pair<double, int> > peaks;
75  for(int p = x; p < x + CARRYOVER_LENGTH - LTS_LENGTH; p++)
76  {
77  std::complex<double> corr(0, 0);
78  double power = 0;
79  for(int s = 0; s < 64; s++)
80  {
81  corr += input[p+s].sample * LTS_TIME_DOMAIN_CONJ[s] /* complex conjugate of LTS */;
82  power += std::norm(input[p+s].sample);
83  }
84  double corr_norm = std::abs(corr) / power;
85  if(corr_norm > LTS_CORR_THRESHOLD) peaks.push_back(std::pair<double, int>(corr_norm, p));
86  }
87 
88  std::sort(peaks.begin(), peaks.end());
89  std::reverse(peaks.begin(), peaks.end());
90 
91  // Look for two peaks, 64 samples apart
92  bool found = false;
93  int jump = 5;
94  for(int s = 0; s < std::min((int)peaks.size(), 3) && !found; s+=jump)
95  {
96  for(int t = s; t < std::min((int)peaks.size(), s+jump) && !found; t++)
97  {
98  if(std::abs(peaks[s].second - peaks[t].second) == 64)
99  {
100  // Determine the LTS offset
101  found = true;
102  int lts_offset = std::min(peaks[s].second, peaks[t].second) - 32; // Start of the LTS CP
103  if(lts_offset < 0) break;
104 
105  input[lts_offset+24].tag = LTS1; // First sample in the LTS
106  input[lts_offset+24+64].tag = LTS2; // First sample in the LTS
107 
108  std::complex<double> auto_corr_acc(0.0, 0.0);
109  for(int k = LTS1; k < LTS1; k++)
110  {
111  auto_corr_acc += input[k].sample * std::conj(input[k+LTS_LENGTH].sample);
112  }
113 
114  m_phase_offset = std::arg(auto_corr_acc) / 64.0;
115  m_phase_acc = std::arg(input[lts_offset + 32 + LTS_LENGTH*2 -1].sample * LTS_TIME_DOMAIN_CONJ[63]);
116  }
117  }
118  }
119  }
120 
122  while(m_phase_acc > 2.0*M_PI) m_phase_acc -= 2.0*M_PI;
123  while(m_phase_acc < -2.0*M_PI) m_phase_acc += 2.0*M_PI;
124  std::complex<double> phase_correction(std::cos(m_phase_acc), std::sin(m_phase_acc));
125  input[x].sample *= phase_correction;
126 
127  }
128 
129  // Copy working samples to output
130  memcpy(&output_buffer[0],
131  &input[0],
132  input_buffer.size() * sizeof(tagged_sample));
133 
134  // Carryover last 160 samples from input buffer
135  memcpy(&m_carryover[0],
136  &input[input_buffer.size()],
137  CARRYOVER_LENGTH * sizeof(tagged_sample));
138 
139  }
140 
141 
142 }