prach.c 62.4 KB
Newer Older
1
/*******************************************************************************
2
    OpenAirInterface
ghaddab's avatar
ghaddab committed
3
    Copyright(c) 1999 - 2014 Eurecom
4

ghaddab's avatar
ghaddab committed
5 6 7 8
    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
9 10


ghaddab's avatar
ghaddab committed
11 12 13 14
    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
15

ghaddab's avatar
ghaddab committed
16
    You should have received a copy of the GNU General Public License
17 18
    along with OpenAirInterface.The full GNU General Public License is
   included in this distribution in the file called "COPYING". If not,
ghaddab's avatar
ghaddab committed
19
   see <http://www.gnu.org/licenses/>.
20 21

  Contact Information
ghaddab's avatar
ghaddab committed
22 23
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
24
  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
25

ghaddab's avatar
ghaddab committed
26
  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
27

ghaddab's avatar
ghaddab committed
28
 *******************************************************************************/
29 30 31 32 33 34 35 36 37 38 39

/*! \file PHY/LTE_TRANSPORT/prach.c
 * \brief Top-level routines for generating and decoding the PRACH physical channel V8.6 2009-03
 * \author R. Knopp
 * \date 2011
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr
 * \note
 * \warning
 */
40
#include "PHY/sse_intrin.h"
41 42 43
#include "PHY/defs.h"
#include "PHY/extern.h"
//#include "prach.h"
44
#include "PHY/LTE_TRANSPORT/if4_tools.h"
45 46 47 48
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "UTIL/LOG/vcd_signal_dumper.h"

Raymond Knopp's avatar
 
Raymond Knopp committed
49
//#define PRACH_DEBUG 1
50

51 52 53
uint16_t NCS_unrestricted[16] = {0,13,15,18,22,26,32,38,46,59,76,93,119,167,279,419};
uint16_t NCS_restricted[15]   = {15,18,22,26,32,38,46,55,68,82,100,128,158,202,237}; // high-speed case
uint16_t NCS_4[7]             = {2,4,6,8,10,12,15};
54

55 56 57
int16_t ru[2*839]; // quantized roots of unity
uint32_t ZC_inv[839]; // multiplicative inverse for roots u
uint16_t du[838];
58 59

typedef struct {
60 61 62 63
  uint8_t f_ra;
  uint8_t t0_ra;
  uint8_t t1_ra;
  uint8_t t2_ra;
64 65
} PRACH_TDD_PREAMBLE_MAP_elem;
typedef struct {
66
  uint8_t num_prach;
67 68 69 70
  PRACH_TDD_PREAMBLE_MAP_elem map[6];
} PRACH_TDD_PREAMBLE_MAP;

// This is table 5.7.1-4 from 36.211
71
PRACH_TDD_PREAMBLE_MAP tdd_preamble_map[64][7] = {
72 73 74 75 76 77 78 79 80 81 82
  // TDD Configuration Index 0
  { {1,{{0,1,0,2}}},{1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {1,{{0,1,0,2}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {1,{{0,1,0,2}}}},
  // TDD Configuration Index 1
  { {1,{{0,2,0,2}}},{1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {1,{{0,2,0,2}}}, {1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {1,{{0,2,0,2}}}},
  // TDD Configuration Index 2
  { {1,{{0,1,1,2}}},{1,{{0,1,1,1}}}, {1,{{0,1,1,0}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,1,1}}}},
  // TDD Configuration Index 3
  { {1,{{0,0,0,2}}},{1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {1,{{0,0,0,2}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {1,{{0,0,0,2}}}},
  // TDD Configuration Index 4
  { {1,{{0,0,1,2}}},{1,{{0,0,1,1}}}, {1,{{0,0,1,0}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,1,1}}}},
  // TDD Configuration Index 5
83
  { {1,{{0,0,0,1}}},{1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}},
84 85 86
  // TDD Configuration Index 6
  { {2,{{0,0,0,2},{0,0,1,2}}}, {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {2,{{0,0,0,1},{0,0,0,2}}}, {2,{{0,0,0,0},{0,0,0,1}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {2,{{0,0,0,2},{0,0,1,1}}}},
  // TDD Configuration Index 7
87
  { {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{0,0,0,2}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{0,0,1,0}}}},
88 89 90 91 92 93 94
  // TDD Configuration Index 8
  { {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{0,0,0,1}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{0,0,1,1}}}},
  // TDD Configuration Index 9
  { {3,{{0,0,0,1},{0,0,0,2},{0,0,1,2}}}, {3,{{0,0,0,0},{0,0,0,1},{0,0,1,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,1},{0,0,0,2}}}, {3,{{0,0,0,0},{0,0,0,1},{1,0,0,1}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {3,{{0,0,0,1},{0,0,0,2},{0,0,1,1}}}},
  // TDD Configuration Index 10
  { {3,{{0,0,0,0},{0,0,1,0},{0,0,1,1}}}, {3,{{0,0,0,1},{0,0,1,0},{0,0,1,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,1},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,2},{0,0,1,0}}}},
  // TDD Configuration Index 11
95
  { {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,1},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{0,0,1,0},{0,0,1,1}}}},
96
  // TDD Configuration Index 12
97
  { {4,{{0,0,0,1},{0,0,0,2},{0,0,1,1},{0,0,1,2}}}, {4,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1}}},
98 99 100 101 102 103 104
    {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}},
    {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,2}}},
    {4,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1}}},
    {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}},
    {4,{{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1}}}
  },
  // TDD Configuration Index 13
105
  { {4,{{0,0,0,0},{0,0,0,2},{0,0,1,0},{0,0,1,2}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
106 107 108 109 110 111 112
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,1}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,1}}}
  },
  // TDD Configuration Index 14
113
  { {4,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
114 115 116 117 118 119 120
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,0},{0,0,0,2},{0,0,1,0},{0,0,1,1}}}
  },
  // TDD Configuration Index 15
121
  { {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,1},{0,0,1,2}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,1}}},
122 123 124 125 126
    {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,1},{1,0,0,2}}},
    {5,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1},{2,0,0,1}}}, {5,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0}}},
    {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1}}}
  },
  // TDD Configuration Index 16
127
  { {5,{{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{0,0,1,2}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,1,1}}},
128 129 130 131 132
    {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,1,0}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0},{1,0,0,2}}},
    {5,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}
  },
  // TDD Configuration Index 17
133
  { {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,2}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,0}}},
134 135 136 137 138
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0},{1,0,0,1}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}
  },
  // TDD Configuration Index 18
139
  { {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{0,0,1,2}}},
140 141 142 143 144 145 146 147
    {6,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,1},{1,0,1,1}}},
    {6,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0},{2,0,1,0}}},
    {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0},{1,0,0,1},{1,0,0,2}}},
    {6,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1},{2,0,0,0},{2,0,0,1}}},
    {6,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0},{5,0,0,0}}},
    {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{1,0,0,2}}}
  },
  // TDD Configuration Index 19
148
  { {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
149 150 151 152 153 154 155 156
    {6,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,0},{1,0,1,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{1,0,1,1}}}
  },
  // TDD Configuration Index 20
157
  { {1,{{0,1,0,1}}},{1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}},
158
  // TDD Configuration Index 21
159 160
  { {1,{{0,2,0,1}}},{1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}},

161
  // TDD Configuration Index 22
162 163
  { {1,{{0,1,1,1}}},{1,{{0,1,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,1,0}}}},

164
  // TDD Configuration Index 23
165 166
  { {1,{{0,0,0,1}}},{1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}},

167
  // TDD Configuration Index 24
168 169 170 171 172
  { {1,{{0,0,1,1}}},{1,{{0,0,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,1,0}}}},

  // TDD Configuration Index 25
  { {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{1,0,0,1}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{0,0,1,0}}}},

173
  // TDD Configuration Index 26
174 175
  { {3,{{0,0,0,1},{0,0,1,1},{1,0,0,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{1,0,0,1},{2,0,0,1}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{0,0,1,0},{1,0,0,1}}}},

176
  // TDD Configuration Index 27
177
  { {4,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1}}}, {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}},
178 179 180 181 182 183 184 185
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1}}},
    {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0}}}
  },

  // TDD Configuration Index 28
186
  { {5,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1}}}, {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0}}},
187 188 189 190
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1}}},
    {5,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {5,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1}}}
  },
191

192
  // TDD Configuration Index 29
193
  { {6,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1},{2,0,1,1}}},
194 195 196 197 198 199 200
    {6,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0},{2,0,1,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {6,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1},{5,0,0,1}}},
    {6,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0},{5,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {6,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1},{2,0,1,0}}}
  },
201 202


203
  // TDD Configuration Index 30
204 205
  { {1,{{0,1,0,1}}},{1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}},

206
  // TDD Configuration Index 31
207 208
  { {1,{{0,2,0,1}}},{1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}},

209
  // TDD Configuration Index 32
210 211
  { {1,{{0,1,1,1}}},{1,{{0,1,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,1,0}}}},

212
  // TDD Configuration Index 33
213 214
  { {1,{{0,0,0,1}}},{1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}},

215
  // TDD Configuration Index 34
216 217
  { {1,{{0,0,1,1}}},{1,{{0,0,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,1,0}}}},

218
  // TDD Configuration Index 35
219 220
  { {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{1,0,0,1}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{0,0,1,0}}}},

221
  // TDD Configuration Index 36
222 223
  { {3,{{0,0,0,1},{0,0,1,1},{1,0,0,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{1,0,0,1},{2,0,0,1}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{0,0,1,0},{1,0,0,1}}}},

224
  // TDD Configuration Index 37
225
  { {4,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1}}}, {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}},
226 227 228 229 230 231 232 233
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1}}},
    {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0}}}
  },

  // TDD Configuration Index 38
234
  { {5,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1}}}, {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0}}},
235 236 237 238
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1}}},
    {5,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {5,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1}}}
  },
239

240
  // TDD Configuration Index 39
241
  { {6,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1},{2,0,1,1}}},
242 243 244 245 246 247 248 249 250
    {6,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0},{2,0,1,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {6,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1},{5,0,0,1}}},
    {6,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0},{5,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {6,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1},{2,0,1,0}}}
  },

  // TDD Configuration Index 40
251
  { {1,{{0,1,0,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,0}}}},
252
  // TDD Configuration Index 41
253 254
  { {1,{{0,2,0,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,0}}}},

255
  // TDD Configuration Index 42
256 257
  { {1,{{0,1,1,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}},

258
  // TDD Configuration Index 43
259 260
  { {1,{{0,0,0,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,0}}}},

261
  // TDD Configuration Index 44
262 263
  { {1,{{0,0,1,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}},

264
  // TDD Configuration Index 45
265 266
  { {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{1,0,0,0}}}},

267
  // TDD Configuration Index 46
268 269
  { {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}},

270
  // TDD Configuration Index 47
271
  { {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
272 273 274 275 276 277
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}},
    {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}}
  }
278 279
};

280 281


282
uint16_t prach_root_sequence_map0_3[838] = { 129, 710, 140, 699, 120, 719, 210, 629, 168, 671, 84, 755, 105, 734, 93, 746, 70, 769, 60, 779,
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
                                             2, 837, 1, 838,
                                             56, 783, 112, 727, 148, 691,
                                             80, 759, 42, 797, 40, 799,
                                             35, 804, 73, 766, 146, 693,
                                             31, 808, 28, 811, 30, 809, 27, 812, 29, 810,
                                             24, 815, 48, 791, 68, 771, 74, 765, 178, 661, 136, 703,
                                             86, 753, 78, 761, 43, 796, 39, 800, 20, 819, 21, 818,
                                             95, 744, 202, 637, 190, 649, 181, 658, 137, 702, 125, 714, 151, 688,
                                             217, 622, 128, 711, 142, 697, 122, 717, 203, 636, 118, 721, 110, 729, 89, 750, 103, 736, 61,
                                             778, 55, 784, 15, 824, 14, 825,
                                             12, 827, 23, 816, 34, 805, 37, 802, 46, 793, 207, 632, 179, 660, 145, 694, 130, 709, 223, 616,
                                             228, 611, 227, 612, 132, 707, 133, 706, 143, 696, 135, 704, 161, 678, 201, 638, 173, 666, 106,
                                             733, 83, 756, 91, 748, 66, 773, 53, 786, 10, 829, 9, 830,
                                             7, 832, 8, 831, 16, 823, 47, 792, 64, 775, 57, 782, 104, 735, 101, 738, 108, 731, 208, 631, 184,
                                             655, 197, 642, 191, 648, 121, 718, 141, 698, 149, 690, 216, 623, 218, 621,
                                             152, 687, 144, 695, 134, 705, 138, 701, 199, 640, 162, 677, 176, 663, 119, 720, 158, 681, 164,
                                             675, 174, 665, 171, 668, 170, 669, 87, 752, 169, 670, 88, 751, 107, 732, 81, 758, 82, 757, 100,
                                             739, 98, 741, 71, 768, 59, 780, 65, 774, 50, 789, 49, 790, 26, 813, 17, 822, 13, 826, 6, 833,
                                             5, 834, 33, 806, 51, 788, 75, 764, 99, 740, 96, 743, 97, 742, 166, 673, 172, 667, 175, 664, 187,
                                             652, 163, 676, 185, 654, 200, 639, 114, 725, 189, 650, 115, 724, 194, 645, 195, 644, 192, 647,
                                             182, 657, 157, 682, 156, 683, 211, 628, 154, 685, 123, 716, 139, 700, 212, 627, 153, 686, 213,
                                             626, 215, 624, 150, 689,
                                             225, 614, 224, 615, 221, 618, 220, 619, 127, 712, 147, 692, 124, 715, 193, 646, 205, 634, 206,
                                             633, 116, 723, 160, 679, 186, 653, 167, 672, 79, 760, 85, 754, 77, 762, 92, 747, 58, 781, 62,
                                             777, 69, 770, 54, 785, 36, 803, 32, 807, 25, 814, 18, 821, 11, 828, 4, 835,
                                             3, 836, 19, 820, 22, 817, 41, 798, 38, 801, 44, 795, 52, 787, 45, 794, 63, 776, 67, 772, 72,
                                             767, 76, 763, 94, 745, 102, 737, 90, 749, 109, 730, 165, 674, 111, 728, 209, 630, 204, 635, 117,
                                             722, 188, 651, 159, 680, 198, 641, 113, 726, 183, 656, 180, 659, 177, 662, 196, 643, 155, 684,
                                             214, 625, 126, 713, 131, 708, 219, 620, 222, 617, 226, 613,
                                             230, 609, 232, 607, 262, 577, 252, 587, 418, 421, 416, 423, 413, 426, 411, 428, 376, 463, 395,
                                             444, 283, 556, 285, 554, 379, 460, 390, 449, 363, 476, 384, 455, 388, 451, 386, 453, 361, 478,
                                             387, 452, 360, 479, 310, 529, 354, 485, 328, 511, 315, 524, 337, 502, 349, 490, 335, 504, 324,
                                             515,
                                             323, 516, 320, 519, 334, 505, 359, 480, 295, 544, 385, 454, 292, 547, 291, 548, 381, 458, 399,
                                             440, 380, 459, 397, 442, 369, 470, 377, 462, 410, 429, 407, 432, 281, 558, 414, 425, 247, 592,
                                             277, 562, 271, 568, 272, 567, 264, 575, 259, 580,
                                             237, 602, 239, 600, 244, 595, 243, 596, 275, 564, 278, 561, 250, 589, 246, 593, 417, 422, 248,
                                             591, 394, 445, 393, 446, 370, 469, 365, 474, 300, 539, 299, 540, 364, 475, 362, 477, 298, 541,
                                             312, 527, 313, 526, 314, 525, 353, 486, 352, 487, 343, 496, 327, 512, 350, 489, 326, 513, 319,
                                             520, 332, 507, 333, 506, 348, 491, 347, 492, 322, 517,
                                             330, 509, 338, 501, 341, 498, 340, 499, 342, 497, 301, 538, 366, 473, 401, 438, 371, 468, 408,
                                             431, 375, 464, 249, 590, 269, 570, 238, 601, 234, 605,
                                             257, 582, 273, 566, 255, 584, 254, 585, 245, 594, 251, 588, 412, 427, 372, 467, 282, 557, 403,
                                             436, 396, 443, 392, 447, 391, 448, 382, 457, 389, 450, 294, 545, 297, 542, 311, 528, 344, 495,
                                             345, 494, 318, 521, 331, 508, 325, 514, 321, 518,
                                             346, 493, 339, 500, 351, 488, 306, 533, 289, 550, 400, 439, 378, 461, 374, 465, 415, 424, 270,
                                             569, 241, 598,
                                             231, 608, 260, 579, 268, 571, 276, 563, 409, 430, 398, 441, 290, 549, 304, 535, 308, 531, 358,
                                             481, 316, 523,
                                             293, 546, 288, 551, 284, 555, 368, 471, 253, 586, 256, 583, 263, 576,
                                             242, 597, 274, 565, 402, 437, 383, 456, 357, 482, 329, 510,
                                             317, 522, 307, 532, 286, 553, 287, 552, 266, 573, 261, 578,
                                             236, 603, 303, 536, 356, 483,
                                             355, 484, 405, 434, 404, 435, 406, 433,
                                             235, 604, 267, 572, 302, 537,
                                             309, 530, 265, 574, 233, 606,
                                             367, 472, 296, 543,
                                             336, 503, 305, 534, 373, 466, 280, 559, 279, 560, 419, 420, 240, 599, 258, 581, 229, 610
                                           };
342

343
uint16_t prach_root_sequence_map4[138] = {  1,138,2,137,3,136,4,135,5,134,6,133,7,132,8,131,9,130,10,129,
344 345 346 347 348 349 350
                                            11,128,12,127,13,126,14,125,15,124,16,123,17,122,18,121,19,120,20,119,
                                            21,118,22,117,23,116,24,115,25,114,26,113,27,112,28,111,29,110,30,109,
                                            31,108,32,107,33,106,34,105,35,104,36,103,37,102,38,101,39,100,40,99,
                                            41,98,42,97,43,96,44,95,45,94,46,93,47,92,48,91,49,90,50,89,
                                            51,88,52,87,53,86,54,85,55,84,56,83,57,82,58,81,59,80,60,79,
                                            61,78,62,77,63,76,64,75,65,74,66,73,67,72,68,71,69,70
                                         };
351 352

#ifdef USER_MODE
353 354
void dump_prach_config(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe)
{
355 356 357 358 359 360 361

  FILE *fd;

  fd = fopen("prach_config.txt","w");
  fprintf(fd,"prach_config: subframe          = %d\n",subframe);
  fprintf(fd,"prach_config: N_RB_UL           = %d\n",frame_parms->N_RB_UL);
  fprintf(fd,"prach_config: frame_type        = %s\n",(frame_parms->frame_type==1) ? "TDD":"FDD");
362

363
  if(frame_parms->frame_type==1) fprintf(fd,"prach_config: tdd_config        = %d\n",frame_parms->tdd_config);
364 365 366

  fprintf(fd,"prach_config: rootSequenceIndex = %d\n",frame_parms->prach_config_common.rootSequenceIndex);
  fprintf(fd,"prach_config: prach_ConfigIndex = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex);
367 368 369 370 371 372 373 374 375
  fprintf(fd,"prach_config: Ncs_config        = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig);
  fprintf(fd,"prach_config: highSpeedFlag     = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.highSpeedFlag);
  fprintf(fd,"prach_config: n_ra_prboffset    = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset);
  fclose(fd);

}
#endif

// This function computes the du
376 377
void fill_du(uint8_t prach_fmt)
{
378

379 380 381
  uint16_t iu,u,p;
  uint16_t N_ZC;
  uint16_t *prach_root_sequence_map;
382 383 384 385

  if (prach_fmt<4) {
    N_ZC = 839;
    prach_root_sequence_map = prach_root_sequence_map0_3;
386
  } else {
387 388 389 390
    N_ZC = 139;
    prach_root_sequence_map = prach_root_sequence_map4;
  }

391
  for (iu=0; iu<(N_ZC-1); iu++) {
392 393 394

    u=prach_root_sequence_map[iu];
    p=1;
395

396 397
    while (((u*p)%N_ZC)!=1)
      p++;
398

399 400
    du[u] = ((p<(N_ZC>>1)) ? p : (N_ZC-p));
  }
401

402 403
}

404 405
uint8_t get_num_prach_tdd(LTE_DL_FRAME_PARMS *frame_parms)
{
406 407 408 409

  return(tdd_preamble_map[frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex][frame_parms->tdd_config].num_prach);
}

410 411
uint8_t get_fid_prach_tdd(LTE_DL_FRAME_PARMS *frame_parms,uint8_t tdd_map_index)
{
412 413 414 415

  return(tdd_preamble_map[frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex][frame_parms->tdd_config].map[tdd_map_index].f_ra);
}

416 417
uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type)
{
418 419 420 421 422 423 424

  if (frame_type == FDD) // FDD
    return(prach_ConfigIndex>>4);

  else {
    if (prach_ConfigIndex < 20)
      return (0);
425

426 427
    if (prach_ConfigIndex < 30)
      return (1);
428

429 430
    if (prach_ConfigIndex < 40)
      return (2);
431

432 433 434 435 436 437 438
    if (prach_ConfigIndex < 48)
      return (3);
    else
      return (4);
  }
}

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms, uint8_t tdd_mapindex, uint16_t Nf) 
{
  lte_frame_type_t frame_type         = frame_parms->frame_type;
  uint8_t tdd_config         = frame_parms->tdd_config;
  uint8_t prach_ConfigIndex  = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
  uint8_t n_ra_prboffset     = frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset;
  uint8_t n_ra_prb;
  uint8_t f_ra,t1_ra;
  uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
  uint8_t Nsp=2;

  if (frame_type == TDD) { // TDD

    if (tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach==0) {
      LOG_E(PHY, "Illegal prach_ConfigIndex %"PRIu8"", prach_ConfigIndex);
      return(-1);
    }

    // adjust n_ra_prboffset for frequency multiplexing (p.36 36.211)
    f_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[tdd_mapindex].f_ra;

    if (prach_fmt < 4) {
      if ((f_ra&1) == 0) {
        n_ra_prb = n_ra_prboffset + 6*(f_ra>>1);
      } else {
        n_ra_prb = frame_parms->N_RB_UL - 6 - n_ra_prboffset + 6*(f_ra>>1);
      }
    } else {
      if ((tdd_config >2) && (tdd_config<6))
        Nsp = 2;

      t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra;

      if ((((Nf&1)*(2-Nsp)+t1_ra)&1) == 0) {
        n_ra_prb = 6*f_ra;
      } else {
        n_ra_prb = frame_parms->N_RB_UL - 6*(f_ra+1);
      }
    }
  }
  else { //FDD
    n_ra_prb = n_ra_prboffset;
  }
  return(n_ra_prb);
}
484

485 486
int is_prach_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t subframe)
{
487

488 489
  uint8_t prach_ConfigIndex  = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
  uint8_t tdd_config         = frame_parms->tdd_config;
490 491 492
  uint8_t t0_ra;
  uint8_t t1_ra;
  uint8_t t2_ra;
493

Raymond Knopp's avatar
 
Raymond Knopp committed
494

495 496 497
  if (frame_parms->frame_type == FDD) { //FDD
    //implement Table 5.7.1-2 from 36.211 (Rel-10, p.41)
    if ((((frame&1) == 1) && (subframe < 9)) ||
498
        (((frame&1) == 0) && (subframe == 9)))  // This is an odd frame, ignore even-only PRACH frames
499
      if (((prach_ConfigIndex&0xf)<3) || // 0,1,2,16,17,18,32,33,34,48,49,50
500 501 502
          ((prach_ConfigIndex&0x1f)==18) || // 18,50
          ((prach_ConfigIndex&0xf)==15))   // 15,47
        return(0);
503 504 505 506 507 508

    switch (prach_ConfigIndex&0x1f) {
    case 0:
    case 3:
      return(subframe==1);
      break;
509

510 511 512 513
    case 1:
    case 4:
      return(subframe==4);
      break;
514

515 516 517 518
    case 2:
    case 5:
      return(subframe==7);
      break;
519

520 521 522
    case 6:
      return((subframe==1) || (subframe==6));
      break;
523

524 525 526
    case 7:
      return((subframe==2) || (subframe==7));
      break;
527

528 529 530
    case 8:
      return((subframe==3) || (subframe==8));
      break;
531

532 533 534
    case 9:
      return((subframe==1) || (subframe==4) || (subframe==7));
      break;
535

536 537 538
    case 10:
      return((subframe==2) || (subframe==5) || (subframe==8));
      break;
539

540 541 542
    case 11:
      return((subframe==3) || (subframe==6) || (subframe==9));
      break;
543

544 545 546
    case 12:
      return((subframe&1)==0);
      break;
547

548 549 550
    case 13:
      return((subframe&1)==1);
      break;
551

552 553 554
    case 14:
      return(1==1);
      break;
555

556 557 558 559
    case 15:
      return(subframe==9);
      break;
    }
560
  } else { // TDD
561 562 563 564 565 566 567 568 569

    if (prach_ConfigIndex>=64) {
      LOG_E(PHY,"[PHY] Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
      return(0);
    }

    if (tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach==0) {
      LOG_E(PHY,"[PHY] Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
      return(0);
570
    }
571 572 573 574

    t0_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t0_ra;
    t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra;
    t2_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t2_ra;
575
#ifdef PRACH_DEBUG
576
    LOG_D(PHY,"[PRACH] Checking for PRACH format (ConfigIndex %d) in TDD subframe %d (%d,%d,%d)\n",
577 578 579 580 581
          prach_ConfigIndex,
          subframe,
          t0_ra,t1_ra,t2_ra);
#endif

582
    if ((((t0_ra == 1) && ((frame &1)==0))||  // frame is even and PRACH is in even frames
583 584 585 586 587 588
         ((t0_ra == 2) && ((frame &1)==1))||  // frame is odd and PRACH is in odd frames
         (t0_ra == 0)) &&                                // PRACH is in all frames
        (((subframe<5)&&(t1_ra==0)) ||                   // PRACH is in 1st half-frame
         (((subframe>4)&&(t1_ra==1))))) {                // PRACH is in 2nd half-frame
      if (prach_ConfigIndex<48)                          // PRACH only in normal UL subframe
        return((((subframe%5)-2)==t2_ra));
589
      else                                               // PRACH can be in UpPTS
590 591
        return((((subframe%5)-1)==t2_ra));
    } else
592 593
      return(1==2);
  }
594

595 596 597 598
  // shouldn't get here!
  return(2==1);
}

599
int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t Nf )
600 601
{

602 603 604 605 606 607 608 609 610 611
  lte_frame_type_t frame_type         = ue->frame_parms.frame_type;
  //uint8_t tdd_config         = ue->frame_parms.tdd_config;
  uint16_t rootSequenceIndex = ue->frame_parms.prach_config_common.rootSequenceIndex;
  uint8_t prach_ConfigIndex  = ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
  uint8_t Ncs_config         = ue->frame_parms.prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
  uint8_t restricted_set     = ue->frame_parms.prach_config_common.prach_ConfigInfo.highSpeedFlag;
  //uint8_t n_ra_prboffset     = ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset;
  uint8_t preamble_index     = ue->prach_resources[eNB_id]->ra_PreambleIndex;
  uint8_t tdd_mapindex       = ue->prach_resources[eNB_id]->ra_TDD_map_index;
  int16_t *prachF           = ue->prach_vars[eNB_id]->prachF;
612
  static int16_t prach_tmp[45600*2] __attribute__((aligned(32)));
613
  int16_t *prach            = prach_tmp;
614
  int16_t *prach2;
615
  int16_t amp               = ue->prach_vars[eNB_id]->amp;
616 617 618 619 620 621
  int16_t Ncp;
  uint8_t n_ra_prb;
  uint16_t NCS;
  uint16_t *prach_root_sequence_map;
  uint16_t preamble_offset,preamble_shift;
  uint16_t preamble_index0,n_shift_ra,n_shift_ra_bar;
622
  uint16_t d_start,numshift;
623 624

  uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
625 626
  //uint8_t Nsp=2;
  //uint8_t f_ra,t1_ra;
627 628
  uint16_t N_ZC = (prach_fmt<4)?839:139;
  uint8_t not_found;
629
  int k;
630 631 632 633
  int16_t *Xu;
  uint16_t u;
  int32_t Xu_re,Xu_im;
  uint16_t offset,offset2;
634 635
  int prach_start;
  int i, prach_len;
636
  uint16_t first_nonzero_root_idx=0;
637

Raymond Knopp's avatar
 
Raymond Knopp committed
638
#if defined(EXMIMO) || defined(OAI_USRP)
639
  prach_start =  (ue->rx_offset+subframe*ue->frame_parms.samples_per_tti-ue->hw_timing_advance-ue->N_TA_offset);
640

641
  if (prach_start<0)
642
    prach_start+=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
643

644 645
  if (prach_start>=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME))
    prach_start-=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
646

647
#else //normal case (simulation)
648
  prach_start = subframe*ue->frame_parms.samples_per_tti-ue->N_TA_offset;
649 650
#endif

651

652 653
  // First compute physical root sequence
  if (restricted_set == 0) {
654 655
    if (Ncs_config > 15) {
      LOG_E( PHY, "[PHY] FATAL, Illegal Ncs_config for unrestricted format %"PRIu8"\n", Ncs_config );
Lionel Gauthier's avatar
Lionel Gauthier committed
656
      mac_xface->macphy_exit("PRACH: Illegal Ncs_config for unrestricted format");
657
      return 0; // not reached
658
    }
659 660 661

    NCS = NCS_unrestricted[Ncs_config];
  } else {
662 663
    if (Ncs_config > 14) {
      LOG_E( PHY, "[PHY] FATAL, Illegal Ncs_config for restricted format %"PRIu8"\n", Ncs_config );
Lionel Gauthier's avatar
Lionel Gauthier committed
664
      mac_xface->macphy_exit("PRACH: Illegal Ncs_config for restricted format");
665
      return 0; // not reached
666
    }
667

668 669 670
    NCS = NCS_restricted[Ncs_config];
  }

671
  n_ra_prb = get_prach_prb_offset(&(ue->frame_parms), tdd_mapindex, Nf);
672
  prach_root_sequence_map = (prach_fmt<4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
673

674 675
  /*
  // this code is not part of get_prach_prb_offset
676 677 678
  if (frame_type == TDD) { // TDD

    if (tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach==0) {
679
      LOG_E( PHY, "[PHY][UE %"PRIu8"] Illegal prach_ConfigIndex %"PRIu8" for ", ue->Mod_id, prach_ConfigIndex );
680
    }
681 682 683

    // adjust n_ra_prboffset for frequency multiplexing (p.36 36.211)
    f_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[tdd_mapindex].f_ra;
684

685 686
    if (prach_fmt < 4) {
      if ((f_ra&1) == 0) {
687 688
        n_ra_prb = n_ra_prboffset + 6*(f_ra>>1);
      } else {
689
        n_ra_prb = ue->frame_parms.N_RB_UL - 6 - n_ra_prboffset + 6*(f_ra>>1);
690
      }
691 692 693 694
    } else {
      if ((tdd_config >2) && (tdd_config<6))
        Nsp = 2;

695
      t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra;
696

697
      if ((((Nf&1)*(2-Nsp)+t1_ra)&1) == 0) {
698 699
        n_ra_prb = 6*f_ra;
      } else {
700
        n_ra_prb = ue->frame_parms.N_RB_UL - 6*(f_ra+1);
701 702 703
      }
    }
  }
704
  */
705 706 707

  // This is the relative offset (for unrestricted case) in the root sequence table (5.7.2-4 from 36.211) for the given preamble index
  preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS)));
708

709
  if (restricted_set == 0) {
710
    // This is the \nu corresponding to the preamble index
711
    preamble_shift  = (NCS==0)? 0 : (preamble_index % (N_ZC/NCS));
712 713
    preamble_shift *= NCS;
  } else { // This is the high-speed case
714 715

#ifdef PRACH_DEBUG
716
    LOG_D(PHY,"[UE %d] High-speed mode, NCS_config %d\n",ue->Mod_id,Ncs_config);
717 718 719 720 721 722 723
#endif

    not_found = 1;
    preamble_index0 = preamble_index;
    // set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this
    // preamble index and find the corresponding cyclic shift
    preamble_offset = 0; // relative rootSequenceIndex;
724

725 726
    while (not_found == 1) {
      // current root depending on rootSequenceIndex and preamble_offset
727
      int index = (rootSequenceIndex + preamble_offset) % N_ZC;
728

729
      if (prach_fmt<4) {
730
        // prach_root_sequence_map points to prach_root_sequence_map0_3
731
        DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
732
      } else {
733
        // prach_root_sequence_map points to prach_root_sequence_map4
734
        DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
735
      }
736

737
      u = prach_root_sequence_map[index];
738

739
      uint16_t n_group_ra = 0;
740

741
      if ( (du[u]<(N_ZC/3)) && (du[u]>=NCS) ) {
742 743 744 745 746 747 748 749 750 751 752 753
        n_shift_ra     = du[u]/NCS;
        d_start        = (du[u]<<1) + (n_shift_ra * NCS);
        n_group_ra     = N_ZC/d_start;
        n_shift_ra_bar = max(0,(N_ZC-(du[u]<<1)-(n_group_ra*d_start))/N_ZC);
      } else if  ( (du[u]>=(N_ZC/3)) && (du[u]<=((N_ZC - NCS)>>1)) ) {
        n_shift_ra     = (N_ZC - (du[u]<<1))/NCS;
        d_start        = N_ZC - (du[u]<<1) + (n_shift_ra * NCS);
        n_group_ra     = du[u]/d_start;
        n_shift_ra_bar = min(n_shift_ra,max(0,(du[u]- (n_group_ra*d_start))/NCS));
      } else {
        n_shift_ra     = 0;
        n_shift_ra_bar = 0;
754
      }
755

756 757 758 759
      // This is the number of cyclic shifts for the current root u
      numshift = (n_shift_ra*n_group_ra) + n_shift_ra_bar;

      if (numshift>0 && preamble_index0==preamble_index)
760
        first_nonzero_root_idx = preamble_offset;
761 762

      if (preamble_index0 < numshift) {
763 764 765 766 767 768
        not_found      = 0;
        preamble_shift = (d_start * (preamble_index0/n_shift_ra)) + ((preamble_index0%n_shift_ra)*NCS);

      } else { // skip to next rootSequenceIndex and recompute parameters
        preamble_offset++;
        preamble_index0 -= numshift;
769 770 771
      }
    }
  }
772

773 774
  // now generate PRACH signal
#ifdef PRACH_DEBUG
775

776 777
  if (NCS>0)
    LOG_D(PHY,"Generate PRACH for RootSeqIndex %d, Preamble Index %d, NCS %d (NCS_config %d, N_ZC/NCS %d) n_ra_prb %d: Preamble_offset %d, Preamble_shift %d\n",
778 779 780
          rootSequenceIndex,preamble_index,NCS,Ncs_config,N_ZC/NCS,n_ra_prb,
          preamble_offset,preamble_shift);

781 782 783 784
#endif

  //  nsymb = (frame_parms->Ncp==0) ? 14:12;
  //  subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*subframe*nsymb;
785

786
  k = (12*n_ra_prb) - 6*ue->frame_parms.N_RB_UL;
787

788
  if (k<0)
789
    k+=ue->frame_parms.ofdm_symbol_size;
790

791 792 793
  k*=12;
  k+=13;

794
  Xu = (int16_t*)ue->X_u[preamble_offset-first_nonzero_root_idx];
795 796

  /*
797 798 799
    k+=(12*ue->frame_parms.first_carrier_offset);
    if (k>(12*ue->frame_parms.ofdm_symbol_size))
    k-=(12*ue->frame_parms.ofdm_symbol_size);
800 801
  */
  k*=2;
802

803
  switch (ue->frame_parms.N_RB_UL) {
804 805 806
  case 6:
    memset((void*)prachF,0,4*1536);
    break;
807

808 809 810
  case 15:
    memset((void*)prachF,0,4*3072);
    break;
811

812 813 814
  case 25:
    memset((void*)prachF,0,4*6144);
    break;
815

816 817 818
  case 50:
    memset((void*)prachF,0,4*12288);
    break;
819

820 821 822
  case 75:
    memset((void*)prachF,0,4*19432);
    break;
823

824 825 826 827 828
  case 100:
    memset((void*)prachF,0,4*24576);
    break;
  }

829
  for (offset=0,offset2=0; offset<N_ZC; offset++,offset2+=preamble_shift) {
830 831 832 833

    if (offset2 >= N_ZC)
      offset2 -= N_ZC;

834 835
    Xu_re = (((int32_t)Xu[offset<<1]*amp)>>15);
    Xu_im = (((int32_t)Xu[1+(offset<<1)]*amp)>>15);
836 837 838
    prachF[k++]= ((Xu_re*ru[offset2<<1]) - (Xu_im*ru[1+(offset2<<1)]))>>15;
    prachF[k++]= ((Xu_im*ru[offset2<<1]) + (Xu_re*ru[1+(offset2<<1)]))>>15;

839
    if (k==(12*2*ue->frame_parms.ofdm_symbol_size))
840 841 842 843 844 845 846
      k=0;
  }

  switch (prach_fmt) {
  case 0:
    Ncp = 3168;
    break;
847

848 849 850 851
  case 1:
  case 3:
    Ncp = 21024;
    break;
852

853 854 855
  case 2:
    Ncp = 6240;
    break;
856

857 858 859
  case 4:
    Ncp = 448;
    break;
860

861 862 863 864 865
  default:
    Ncp = 3168;
    break;
  }

866
  switch (ue->frame_parms.N_RB_UL) {
867 868 869 870
  case 6:
    Ncp>>=4;
    prach+=4; // makes prach2 aligned to 128-bit
    break;
871

872 873 874
  case 15:
    Ncp>>=3;
    break;
875

876 877 878
  case 25:
    Ncp>>=2;
    break;
879

880 881 882
  case 50:
    Ncp>>=1;
    break;
883

884 885 886 887 888 889
  case 75:
    Ncp=(Ncp*3)>>2;
    break;
  }

  prach2 = prach+(Ncp<<1);
890

891
  // do IDFT
892
  switch (ue->frame_parms.N_RB_UL) {
893 894
  case 6:
    if (prach_fmt == 4) {
895
      idft256(prachF,prach2,1);
896 897
      memmove( prach, prach+512, Ncp<<2 );
      prach_len = 256+Ncp;
898
    } else {
899
      idft1536(prachF,prach2,1);
900
      memmove( prach, prach+3072, Ncp<<2 );
901
      prach_len = 1536+Ncp;
902

903
      if (prach_fmt>1) {
904
        memmove( prach2+3072, prach2, 6144 );
905
        prach_len = 2*1536+Ncp;
906 907
      }
    }
908

909
    break;
910

911 912
  case 15:
    if (prach_fmt == 4) {
913 914
      idft512(prachF,prach2,1);
      //TODO: account for repeated format in dft output
915
      memmove( prach, prach+1024, Ncp<<2 );
916
      prach_len = 512+Ncp;
917
    } else {
918
      idft3072(prachF,prach2);
919
      memmove( prach, prach+6144, Ncp<<2 );
920
      prach_len = 3072+Ncp;
921

922
      if (prach_fmt>1) {
923
        memmove( prach2+6144, prach2, 12288 );
924
        prach_len = 2*3072+Ncp;
925 926
      }
    }
927

928
    break;
929

930 931 932
  case 25:
  default:
    if (prach_fmt == 4) {
933
      idft1024(prachF,prach2,1);
934
      memmove( prach, prach+2048, Ncp<<2 );
935
      prach_len = 1024+Ncp;
936
    } else {
937
      idft6144(prachF,prach2);
938
      /*for (i=0;i<6144*2;i++)
939
      prach2[i]<<=1;*/
940
      memmove( prach, prach+12288, Ncp<<2 );
941
      prach_len = 6144+Ncp;
942 943

      if (prach_fmt>1) {
944
        memmove( prach2+12288, prach2, 24576 );
945
        prach_len = 2*6144+Ncp;
946 947
      }
    }
948

949
    break;
950

951 952
  case 50:
    if (prach_fmt == 4) {
953
      idft2048(prachF,prach2,1);
954
      memmove( prach, prach+4096, Ncp<<2 );
955
      prach_len = 2048+Ncp;
956
    } else {
957
      idft12288(prachF,prach2);
958
      memmove( prach, prach+24576, Ncp<<2 );
959
      prach_len = 12288+Ncp;
960

961
      if (prach_fmt>1) {
962
        memmove( prach2+24576, prach2, 49152 );
963
        prach_len = 2*12288+Ncp;
964 965
      }
    }
966

967
    break;
968

969 970
  case 75:
    if (prach_fmt == 4) {
971 972
      idft3072(prachF,prach2);
      //TODO: account for repeated format in dft output
973
      memmove( prach, prach+6144, Ncp<<2 );
974
      prach_len = 3072+Ncp;
975
    } else {
976
      idft18432(prachF,prach2);
977
      memmove( prach, prach+36864, Ncp<<2 );
978
      prach_len = 18432+Ncp;
979

980
      if (prach_fmt>1) {
981
        memmove( prach2+36834, prach2, 73728 );
982
        prach_len = 2*18432+Ncp;
983 984
      }
    }
985

986
    break;
987

988 989
  case 100:
    if (prach_fmt == 4) {
990
      idft4096(prachF,prach2,1);
991
      memmove( prach, prach+8192, Ncp<<2 );
992
      prach_len = 4096+Ncp;
993
    } else {
994
      idft24576(prachF,prach2);
995
      memmove( prach, prach+49152, Ncp<<2 );
996
      prach_len = 24576+Ncp;
997

998
      if (prach_fmt>1) {
999
        memmove( prach2+49152, prach2, 98304 );
1000
        prach_len = 2* 24576+Ncp;
1001
      }
1002 1003
    }

1004 1005 1006 1007
    break;
  }

  //LOG_D(PHY,"prach_len=%d\n",prach_len);
1008

1009
  if (prach_fmt==4) {
1010
    LOG_E( PHY, "prach_fmt4 not fully implemented" );
Lionel Gauthier's avatar
Lionel Gauthier committed
1011
    mac_xface->macphy_exit("prach_fmt4 not fully implemented");
1012
    return 0; // not reached
1013
  } else {
1014
#if defined(EXMIMO) || defined(OAI_USRP)
1015
    int j;
1016
    int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*ue->frame_parms.samples_per_tti;
1017
    LOG_D( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow );
1018

1019 1020 1021
    for (i=prach_start,j=0; i<min(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,prach_start+prach_len); i++,j++) {
      ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j]<<4;
      ((int16_t*)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1]<<4;
1022
    }
1023 1024

    for (i=0; i<overflow; i++,j++) {
1025 1026
      ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j]<<4;
      ((int16_t*)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1]<<4;
1027
    }
1028 1029
#if defined(EXMIMO)
	    // handle switch before 1st TX subframe, guarantee that the slot prior to transmission is switch on
1030
	    for (k=prach_start - (ue->frame_parms.samples_per_tti>>1) ; k<prach_start ; k++) {
1031
	      if (k<0)
1032 1033 1034
		ue->common_vars.txdata[0][k+ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME] &= 0xFFFEFFFE;
	      else if (k>(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME))
		ue->common_vars.txdata[0][k-ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME] &= 0xFFFEFFFE;
1035
	      else
1036
		ue->common_vars.txdata[0][k] &= 0xFFFEFFFE;
1037 1038
	    }
#endif
1039
#else
1040

1041
    for (i=0; i<prach_len; i++) {
1042 1043
      ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i] = prach[2*i];
      ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i+1] = prach[2*i+1];
1044
    }
1045

1046 1047
#endif
  }
1048

1049 1050 1051 1052 1053 1054

#ifdef PRACH_DEBUG
  write_output("prach_txF0.m","prachtxF0",prachF,prach_len-Ncp,1,1);
  write_output("prach_tx0.m","prachtx0",prach+(Ncp<<1),prach_len-Ncp,1,1);
#endif

1055
  return signal_energy( (int*)prach, 256 );
1056
}
1057
//__m128i mmtmpX0,mmtmpX1,mmtmpX2,mmtmpX3;
1058

1059
void rx_prach(PHY_VARS_eNB *eNB,
1060 1061 1062 1063
	      uint16_t *preamble_energy_list, 
	      uint16_t *preamble_delay_list, 
	      uint16_t Nf, 
	      uint8_t tdd_mapindex)
1064
{
1065 1066

  int i;
1067
  lte_frame_type_t frame_type = eNB->frame_parms.frame_type;
1068
  int subframe                = eNB->proc.subframe_rx;
1069 1070 1071 1072 1073 1074 1075 1076
  uint16_t rootSequenceIndex  = eNB->frame_parms.prach_config_common.rootSequenceIndex;
  uint8_t prach_ConfigIndex   = eNB->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
  uint8_t Ncs_config          = eNB->frame_parms.prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
  uint8_t restricted_set      = eNB->frame_parms.prach_config_common.prach_ConfigInfo.highSpeedFlag;
  int16_t *prachF             = eNB->prach_vars.prachF;
  int16_t **rxsigF            = eNB->prach_vars.rxsigF;
  int16_t **prach_ifft        = eNB->prach_vars.prach_ifft;
  int16_t *prach[eNB->frame_parms.nb_antennas_rx];
1077 1078 1079 1080 1081 1082 1083 1084
  int16_t *prach2;
  uint8_t n_ra_prb;
  uint8_t preamble_index;
  uint16_t NCS,NCS2;
  uint16_t preamble_offset=0,preamble_offset_old;
  int16_t preamble_shift=0;
  uint32_t preamble_shift2;
  uint16_t preamble_index0=0,n_shift_ra=0,n_shift_ra_bar;
1085
  uint16_t d_start=0;
1086 1087 1088 1089 1090
  uint16_t numshift=0;
  uint16_t *prach_root_sequence_map;
  uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
  uint16_t N_ZC = (prach_fmt <4)?839:139;
  uint8_t not_found;
1091
  int k;
1092 1093 1094 1095
  uint16_t u;
  int16_t *Xu;
  uint16_t offset;
  int16_t Ncp;
1096
  uint16_t first_nonzero_root_idx=0;
1097 1098 1099
  uint8_t new_dft=0;
  uint8_t aa;
  int32_t lev;
Raymond Knopp's avatar
 
Raymond Knopp committed
1100
  int16_t levdB;
1101
  int fft_size,log2_ifft_size;
1102
  uint8_t nb_ant_rx = 1; //eNB->frame_parms.nb_antennas_rx;
1103 1104

  for (aa=0; aa<nb_ant_rx; aa++) {
1105
    prach[aa] = (int16_t*)&eNB->common_vars.rxdata[0][aa][subframe*eNB->frame_parms.samples_per_tti-eNB->N_TA_offset];
1106
  }
Sandeep Kumar's avatar
Sandeep Kumar committed
1107

1108 1109 1110 1111
  // First compute physical root sequence
  if (restricted_set == 0) {
    if (Ncs_config>15) {
      LOG_E(PHY,"FATAL, Illegal Ncs_config for unrestricted format %d\n",Ncs_config);
Lionel Gauthier's avatar
Lionel Gauthier committed
1112
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for unrestricted format");
1113
      return; // not reached
1114
    }
1115 1116 1117

    NCS = NCS_unrestricted[Ncs_config];
  } else {
1118 1119
    if (Ncs_config>14) {
      LOG_E(PHY,"FATAL, Illegal Ncs_config for restricted format %d\n",Ncs_config);
Lionel Gauthier's avatar
Lionel Gauthier committed
1120
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for restricted format");
1121
      return; // not reached
1122
    }
1123

1124 1125 1126
    NCS = NCS_restricted[Ncs_config];
  }

1127
  start_meas(&eNB->rx_prach);
1128

1129
  n_ra_prb = get_prach_prb_offset(&(eNB->frame_parms),tdd_mapindex,Nf);
1130
  prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
1131

1132 1133 1134
  // PDP is oversampled, e.g. 1024 sample instead of 839
  // Adapt the NCS (zero-correlation zones) with oversampling factor e.g. 1024/839
  NCS2 = (N_ZC==839) ? ((NCS<<10)/839) : ((NCS<<8)/139);
1135

1136
  if (NCS2==0)
1137
    NCS2 = N_ZC;
1138 1139 1140 1141

  switch (prach_fmt) {
  case 0:
    Ncp = 3168;
1142 1143
    break;

1144 1145 1146 1147
  case 1:
  case 3:
    Ncp = 21024;
    break;
1148

1149 1150 1151
  case 2:
    Ncp = 6240;
    break;
1152

1153 1154 1155
  case 4:
    Ncp = 448;
    break;
1156

1157 1158 1159 1160
  default:
    Ncp = 3168;
    break;
  }
1161

1162
  switch (eNB->frame_parms.N_RB_UL) {
1163 1164 1165
  case 6:
    Ncp>>=4;
    break;
1166

1167 1168 1169
  case 15:
    Ncp>>=3;
    break;
1170

1171 1172 1173
  case 25:
    Ncp>>=2;
    break;
1174

1175 1176 1177
  case 50:
    Ncp>>=1;
    break;
1178

1179 1180 1181 1182 1183
  case 75:
    Ncp=(Ncp*3)>>2;
    break;
  }

1184 1185

  if ((eNB->node_function == eNodeB_3GPP) ||
1186
      (eNB->node_function == NGFI_RRU_IF4p5)) { // compute the DFTs of the PRACH temporal resources
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
    // Do forward transform
    for (aa=0; aa<nb_ant_rx; aa++) {
      prach2 = prach[aa] + (Ncp<<1);
  
      // do DFT
      switch (eNB->frame_parms.N_RB_UL) {
      case 6:
	if (prach_fmt == 4) {
	  dft256(prach2,rxsigF[aa],1);
	} else {
	  dft1536(prach2,rxsigF[aa],1);
	  
	  if (prach_fmt>1)
	    dft1536(prach2+3072,rxsigF[aa]+3072,1);
	}
	
	break;
	
      case 15:
	if (prach_fmt == 4) {
	  dft256(prach2,rxsigF[aa],1);
	} else {
	  dft3072(prach2,rxsigF[aa]);
	  
	  if (prach_fmt>1)
	    dft3072(prach2+6144,rxsigF[aa]+6144);
	}
	
	break;
	
      case 25:
      default:
	if (prach_fmt == 4) {
	  dft1024(prach2,rxsigF[aa],1);
	  fft_size = 1024;
	} else {
	  dft6144(prach2,rxsigF[aa]);
	  
	  if (prach_fmt>1)
	    dft6144(prach2+12288,rxsigF[aa]+12288);
	  
	  fft_size = 6144;
	}
	
	break;
	
      case 50:
	if (prach_fmt == 4) {
	  dft2048(prach2,rxsigF[aa],1);
	} else {
	  dft12288(prach2,rxsigF[aa]);
	  
	  if (prach_fmt>1)
	    dft12288(prach2+24576,rxsigF[aa]+24576);
	}
	
	break;
	
      case 75:
	if (prach_fmt == 4) {
	  dft3072(prach2,rxsigF[aa]);
	} else {
	  dft18432(prach2,rxsigF[aa]);
	  
	  if (prach_fmt>1)
	    dft18432(prach2+36864,rxsigF[aa]+36864);
	}
	
	break;
	
      case 100:
	if (prach_fmt == 4) {
	  dft4096(prach2,rxsigF[aa],1);
	} else {
	  dft24576(prach2,rxsigF[aa]);
	  
	  if (prach_fmt>1)
	    dft24576(prach2+49152,rxsigF[aa]+49152);
	}
	
	break;
      }
    }
  }

1272
  if (eNB->node_function == NGFI_RRU_IF4p5) {
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
    k = (12*n_ra_prb) - 6*eNB->frame_parms.N_RB_UL;
    
    if (k<0) {
      k+=(eNB->frame_parms.ofdm_symbol_size);
    }

    k*=12;
    k+=13; 
    k*=2;
    
    /// **** send_IF4 of rxsigF to RCC **** ///    
1284
    send_IF4p5(eNB, eNB->proc.frame_rx, eNB->proc.subframe_rx, IF4p5_PRACH, k);
1285

1286
    return;
1287
  } else if (eNB->node_function == NGFI_RCC_IF4p5) {
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
    k = (12*n_ra_prb) - 6*eNB->frame_parms.N_RB_UL;
    
    if (k<0) {
      k+=(eNB->frame_parms.ofdm_symbol_size);
    }

    k*=12;
    k+=13; 
    k*=2;

    // Adjust received rxsigF offset    
    memmove((&rxsigF[0][k]),
            (&rxsigF[0][0]),
            839*2*sizeof(int16_t));     
1302
  }
1303
  
1304
  // in case of RCC and prach received rx_thread wakes up prach
1305

1306
  // here onwards is for eNodeB_3GPP or NGFI_RCC_IF4p5
1307

1308 1309
  preamble_offset_old = 99;

1310 1311
  for (preamble_index=0 ; preamble_index<64 ; preamble_index++) {
    if (restricted_set == 0) {
1312 1313
      // This is the relative offset in the root sequence table (5.7.2-4 from 36.211) for the given preamble index
      preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS)));
1314
      
1315
      if (preamble_offset != preamble_offset_old) {
1316 1317 1318 1319
        preamble_offset_old = preamble_offset;
        new_dft = 1;
        // This is the \nu corresponding to the preamble index
        preamble_shift  = 0;
1320
      }
1321
      
1322
      else {
1323
        preamble_shift  -= NCS;
1324
	
1325 1326
        if (preamble_shift < 0)
          preamble_shift+=N_ZC;
1327
      }
1328
    } else { // This is the high-speed case
1329
      new_dft = 0;
1330

1331 1332 1333 1334
      // set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this
      // preamble index and find the corresponding cyclic shift
      // Check if all shifts for that root have been processed
      if (preamble_index0 == numshift) {
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
        not_found = 1;
        new_dft   = 1;
        preamble_index0 -= numshift;
        (preamble_offset==0 && numshift==0) ? (preamble_offset) : (preamble_offset++);

        while (not_found == 1) {
          // current root depending on rootSequenceIndex
          int index = (rootSequenceIndex + preamble_offset) % N_ZC;

          if (prach_fmt<4) {
            // prach_root_sequence_map points to prach_root_sequence_map0_3
1346
            DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
1347 1348
          } else {
            // prach_root_sequence_map points to prach_root_sequence_map4
1349
            DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
1350 1351 1352 1353
          }

          u = prach_root_sequence_map[index];

1354
          uint16_t n_group_ra = 0;
1355

1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
          if ( (du[u]<(N_ZC/3)) && (du[u]>=NCS) ) {
            n_shift_ra     = du[u]/NCS;
            d_start        = (du[u]<<1) + (n_shift_ra * NCS);
            n_group_ra     = N_ZC/d_start;
            n_shift_ra_bar = max(0,(N_ZC-(du[u]<<1)-(n_group_ra*d_start))/N_ZC);
          } else if  ( (du[u]>=(N_ZC/3)) && (du[u]<=((N_ZC - NCS)>>1)) ) {
            n_shift_ra     = (N_ZC - (du[u]<<1))/NCS;
            d_start        = N_ZC - (du[u]<<1) + (n_shift_ra * NCS);
            n_group_ra     = du[u]/d_start;
            n_shift_ra_bar = min(n_shift_ra,max(0,(du[u]- (n_group_ra*d_start))/NCS));
          } else {
            n_shift_ra     = 0;
            n_shift_ra_bar = 0;
          }

          // This is the number of cyclic shifts for the current root u
          numshift = (n_shift_ra*n_group_ra) + n_shift_ra_bar;
          // skip to next root and recompute parameters if numshift==0
          (numshift>0) ? (not_found = 0) : (preamble_offset++);
        }
1376
      }
1377 1378 1379

      if (n_shift_ra>0)
        preamble_shift = -((d_start * (preamble_index0/n_shift_ra)) + ((preamble_index0%n_shift_ra)*NCS)); // minus because the channel is h(t -\tau + Cv)
1380
      else
1381
        preamble_shift = 0;
1382

1383 1384
      if (preamble_shift < 0)
        preamble_shift+=N_ZC;
1385

1386
      preamble_index0++;
1387

1388
      if (preamble_index == 0)
1389
        first_nonzero_root_idx = preamble_offset;
1390
    }
1391

1392 1393 1394 1395 1396 1397
    // Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex
#ifdef PRACH_DEBUG
    LOG_I(PHY,"preamble index %d: offset %d, preamble shift %d\n",preamble_index,preamble_offset,preamble_shift);
#endif
    log2_ifft_size = 10;
    fft_size = 6144;
1398

1399 1400
    if (new_dft == 1) {
      new_dft = 0;
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
      Xu=(int16_t*)eNB->X_u[preamble_offset-first_nonzero_root_idx];
      


      
      k = (12*n_ra_prb) - 6*eNB->frame_parms.N_RB_UL;
      
      if (k<0)
	k+=(eNB->frame_parms.ofdm_symbol_size);
      
      k*=12;
      k+=13; // phi + K/2
      //      k+=(12*eNB->frame_parms.first_carrier_offset);
      //      if (k>(12*eNB->frame_parms.ofdm_symbol_size))
      //  k-=(12*eNB->frame_parms.ofdm_symbol_size);
      
      // printf("First prach carrier : k %d\n",k);
      k*=2;
      

      
      memset( prachF, 0, sizeof(int16_t)*2*1024 );
1423
#ifdef PRACH_DEBUG
1424
      write_output("prach_rx0.m","prach_rx0",prach[0],6144+792,1,1);
1425
#endif
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
      // write_output("prach_rx1.m","prach_rx1",prach[1],6144+792,1,1);
      //       write_output("prach_rxF0.m","prach_rxF0",rxsigF[0],24576,1,1);
      // write_output("prach_rxF1.m","prach_rxF1",rxsigF[1],6144,1,1);

      for (aa=0;aa<nb_ant_rx; aa++) {
      // Do componentwise product with Xu*
	
	for (offset=0; offset<(N_ZC<<1); offset+=2) {
	  prachF[offset]   = (int16_t)(((int32_t)Xu[offset]*rxsigF[aa][k]   + (int32_t)Xu[offset+1]*rxsigF[aa][k+1])>>15);
	  prachF[offset+1] = (int16_t)(((int32_t)Xu[offset]*rxsigF[aa][k+1] - (int32_t)Xu[offset+1]*rxsigF[aa][k])>>15);
	  /*
	    if (offset<16)
	    printf("Xu[%d] %d %d, rxsigF[%d][%d] %d %d\n",offset,Xu[offset],Xu[offset+1],aa,k,rxsigF[aa][k],rxsigF[aa][k+1]);
	  */
	  /*
	    mmtmpX0 = _mm_madd_epi16(*(__m128i*)&Xu[offset],*(__m128i*)&rxsigF[aa][k<<1]);
	    mmtmpX1 = _mm_shufflelo_epi16(*(__m128i*)&Xu[offset],_MM_SHUFFLE(2,3,0,1));
	    mmtmpX1 = _mm_shufflehi_epi16(mmtmpX1,_MM_SHUFFLE(2,3,0,1));
	    mmtmpX1 = _mm_sign_epi16(mmtmpX1,*(__m128i*)&conjugate[0]);
	    mmtmpX1 = _mm_madd_epi16(mmtmpX1,*(__m128i*)&rxsigF[aa][k<<1]);
	    mmtmpX0 = _mm_srai_epi32(mmtmpX0,15);
	    mmtmpX1 = _mm_srai_epi32(mmtmpX1,15);
	    mmtmpX2 = _mm_unpacklo_epi32(mmtmpX0,mmtmpX1);
	    mmtmpX3 = _mm_unpackhi_epi32(mmtmpX0,mmtmpX1);
	    *(__m128i*)&prachF[offset] = _mm_packs_epi32(mmtmpX2,mmtmpX3);
	    */
	  k+=2;
	  
	  if (k==(12*2*eNB->frame_parms.ofdm_symbol_size))
	    k=0;
	}
	
	// Now do IFFT of size 1024 (N_ZC=839) or 256 (N_ZC=139)
	if (N_ZC == 839) {
	  log2_ifft_size = 10;
	  idft1024(prachF,prach_ifft[aa],1);
	} else {
	  idft256(prachF,prach_ifft[aa],1);
	  log2_ifft_size = 8;
	}
1466
#ifdef PRACH_DEBUG
1467
	if (aa==0) write_output("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
1468
#endif
1469
      // if (aa=1) write_output("prach_rxF_comp1.m","prach_rxF_comp1",prachF,1024,1,1);
1470
      }// antennas_rx
1471 1472 1473
#ifdef PRACH_DEBUG
      write_output("prach_ifft0.m","prach_t0",prach_ifft[0],2048,1,1);
#endif
1474
      // write_output("prach_ifft1.m","prach_t1",prach_ifft[1],2048,1,1);
1475
      
1476
    } // new dft
1477
    
1478 1479 1480
    // check energy in nth time shift
    preamble_shift2 = ((preamble_shift==0) ? 0 : ((preamble_shift<<log2_ifft_size)/N_ZC));
    preamble_energy_list[preamble_index] = 0;
1481
    
1482
    for (i=0; i<NCS2; i++) {
1483
      lev = 0;
1484
      
1485
      for (aa=0; aa<nb_ant_rx; aa++) {
1486
	lev += (int32_t)prach_ifft[aa][(preamble_shift2+i)<<1]*prach_ifft[aa][(preamble_shift2+i)<<1] + (int32_t)prach_ifft[aa][1+((preamble_shift2+i)<<1)]*prach_ifft[aa][1+((preamble_shift2+i)<<1)];
1487
      }
1488
      
1489
      levdB = dB_fixed_times10(lev);
1490
      
1491
      if (levdB>preamble_energy_list[preamble_index] ) {
1492 1493
	preamble_energy_list[preamble_index]  = levdB;
	preamble_delay_list[preamble_index]   = (i*fft_size)>>log2_ifft_size;
1494
      }
1495
    }
1496
    
1497
#ifdef PRACH_DEBUG
1498
    LOG_D(PHY,"[RAPROC] Preamble %d => %d dB, %d (shift %d (%d), NCS2 %d(%d), Ncp %d)\n",preamble_index,preamble_energy_list[preamble_index],preamble_delay_list[preamble_index],preamble_shift2,
1499
	  preamble_shift, NCS2,NCS,Ncp);
1500 1501 1502
#endif
    //  exit(-1);
  }// preamble_index
1503 1504 1505
  
  stop_meas(&eNB->rx_prach);
  
1506 1507
}

1508 1509
void init_prach_tables(int N_ZC)
{
1510 1511 1512 1513 1514 1515

  int i,m;

  // Compute the modular multiplicative inverse 'iu' of u s.t. iu*u = 1 mod N_ZC
  ZC_inv[0] = 0;
  ZC_inv[1] = 1;
1516 1517 1518

  for (i=2; i<N_ZC; i++) {
    for (m=2; m<N_ZC; m++)
1519
      if (((i*m)%N_ZC) == 1) {
1520 1521
        ZC_inv[i] = m;
        break;
1522
      }
1523

1524
#ifdef PRACH_DEBUG
1525

1526 1527
    if (i<16)
      printf("i %d : inv %d\n",i,ZC_inv[i]);
1528

1529 1530 1531 1532
#endif
  }

  // Compute quantized roots of unity
1533 1534 1535
  for (i=0; i<N_ZC; i++) {
    ru[i<<1]     = (int16_t)(floor(32767.0*cos(2*M_PI*(double)i/N_ZC)));
    ru[1+(i<<1)] = (int16_t)(floor(32767.0*sin(2*M_PI*(double)i/N_ZC)));
1536
#ifdef PRACH_DEBUG
1537

1538 1539
    if (i<16)
      printf("i %d : runity %d,%d\n",i,ru[i<<1],ru[1+(i<<1)]);
1540

1541 1542 1543 1544 1545
#endif
  }
}

void compute_prach_seq(PRACH_CONFIG_COMMON *prach_config_common,
1546 1547 1548
                       lte_frame_type_t frame_type,
                       uint32_t X_u[64][839])
{
1549 1550 1551 1552

  // Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC)
  unsigned int k,inv_u,i,NCS=0,num_preambles;
  int N_ZC;
1553
  uint8_t prach_fmt = get_prach_fmt(prach_config_common->prach_ConfigInfo.prach_ConfigIndex,frame_type);
1554 1555
  uint16_t *prach_root_sequence_map;
  uint16_t u, preamble_offset;
1556
  uint16_t n_shift_ra,n_shift_ra_bar, d_start,numshift;
1557
  uint8_t not_found;
1558

1559
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_IN);
1560 1561 1562 1563 1564 1565

#ifdef PRACH_DEBUG
  LOG_I(PHY,"compute_prach_seq: NCS_config %d, prach_fmt %d\n",prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig, prach_fmt);
#endif

  if (prach_fmt>=4) {
1566
    LOG_E( PHY, "PRACH sequence is only precomputed for prach_fmt<4 (have %"PRIu8")\n", prach_fmt );
Lionel Gauthier's avatar
Lionel Gauthier committed
1567
    mac_xface->macphy_exit("PRACH sequence is only precomputed for prach_fmt<4");
1568
    return; // not reached
1569 1570 1571 1572 1573
  }

  N_ZC = (prach_fmt < 4) ? 839 : 139;
  //init_prach_tables(N_ZC); //moved to phy_init_lte_ue/eNB, since it takes to long in real-time

1574 1575 1576 1577 1578 1579
  if (prach_fmt < 4) {
    prach_root_sequence_map = prach_root_sequence_map0_3;
  } else {
    // FIXME cannot be reached
    prach_root_sequence_map = prach_root_sequence_map4;
  }
1580 1581 1582


#ifdef PRACH_DEBUG
1583
  LOG_I( PHY, "compute_prach_seq: done init prach_tables\n" );
1584 1585
#endif

1586
  if (prach_config_common->prach_ConfigInfo.highSpeedFlag== 0) {
1587

1588 1589 1590
#ifdef PRACH_DEBUG
    LOG_I(PHY,"Low speed prach : NCS_config %d\n",prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig);
#endif
1591

1592
    if (prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig>15) {
1593
      LOG_E( PHY, "FATAL, Illegal Ncs_config for unrestricted format %"PRIu8"\n", prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig );
Lionel Gauthier's avatar
Lionel Gauthier committed
1594
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for unrestricted format");
1595
      return; // not reached
1596
    } else {
1597 1598
      NCS = NCS_unrestricted[prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig];
    }
1599

1600
    num_preambles = (NCS==0) ? 64 : ((64*NCS)/N_ZC);
1601

1602
    if (NCS>0) num_preambles++;
1603

1604
    preamble_offset = 0;
1605 1606
  } else {

1607
#ifdef PRACH_DEBUG
1608
    LOG_I( PHY, "high speed prach : NCS_config %"PRIu8"\n", prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig );
1609
#endif
1610

1611
    if (prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig>14) {
1612
      LOG_E( PHY, "FATAL, Illegal Ncs_config for restricted format %"PRIu8"\n", prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig );
Lionel Gauthier's avatar
Lionel Gauthier committed
1613
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for restricted format");
1614
      return; // not reached
1615
    } else {
1616 1617 1618
      NCS = NCS_restricted[prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig];
      fill_du(prach_fmt);
    }
1619

1620 1621 1622 1623
    num_preambles = 64; // compute ZC sequence for 64 possible roots
    // find first non-zero shift root (stored in preamble_offset)
    not_found = 1;
    preamble_offset = 0;
1624

1625
    while (not_found == 1) {
1626
      // current root depending on rootSequenceIndex
1627
      int index = (prach_config_common->rootSequenceIndex + preamble_offset) % N_ZC;
1628

1629
      if (prach_fmt<4) {
1630
        // prach_root_sequence_map points to prach_root_sequence_map0_3
1631
        DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
1632
      } else {
1633
        // prach_root_sequence_map points to prach_root_sequence_map4
1634
        DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
1635
      }
1636

1637
      u = prach_root_sequence_map[index];
1638

1639
      uint16_t n_group_ra = 0;
1640

1641
      if ( (du[u]<(N_ZC/3)) && (du[u]>=NCS) ) {
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
        n_shift_ra     = du[u]/NCS;
        d_start        = (du[u]<<1) + (n_shift_ra * NCS);
        n_group_ra     = N_ZC/d_start;
        n_shift_ra_bar = max(0,(N_ZC-(du[u]<<1)-(n_group_ra*d_start))/N_ZC);
      } else if  ( (du[u]>=(N_ZC/3)) && (du[u]<=((N_ZC - NCS)>>1)) ) {
        n_shift_ra     = (N_ZC - (du[u]<<1))/NCS;
        d_start        = N_ZC - (du[u]<<1) + (n_shift_ra * NCS);
        n_group_ra     = du[u]/d_start;
        n_shift_ra_bar = min(n_shift_ra,max(0,(du[u]- (n_group_ra*d_start))/NCS));
      } else {
        n_shift_ra     = 0;
        n_shift_ra_bar = 0;
1654
      }
1655

1656 1657
      // This is the number of cyclic shifts for the current root u
      numshift = (n_shift_ra*n_group_ra) + n_shift_ra_bar;
1658

1659
      // skip to next root and recompute parameters if numshift==0
1660 1661 1662 1663
      if (numshift>0)
        not_found = 0;
      else
        preamble_offset++;
1664 1665 1666 1667
    }
  }

#ifdef PRACH_DEBUG
1668

1669
  if (NCS>0)
1670 1671
    LOG_I( PHY, "Initializing %u preambles for PRACH (NCS_config %"PRIu8", NCS %u, N_ZC/NCS %u)\n",
           num_preambles, prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig, NCS, N_ZC/NCS );
1672

1673 1674
#endif

1675
  for (i=0; i<num_preambles; i++) {
1676
    int index = (prach_config_common->rootSequenceIndex+i+preamble_offset) % N_ZC;
1677

1678
    if (prach_fmt<4) {
1679
      // prach_root_sequence_map points to prach_root_sequence_map0_3
1680
      DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
1681
    } else {
1682
      // prach_root_sequence_map points to prach_root_sequence_map4
1683
      DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
1684
    }
1685

1686
    u = prach_root_sequence_map[index];
1687

1688
    inv_u = ZC_inv[u]; // multiplicative inverse of u
1689

1690 1691 1692 1693

    // X_u[0] stores the first ZC sequence where the root u has a non-zero number of shifts
    // for the unrestricted case X_u[0] is the first root indicated by the rootSequenceIndex

1694 1695 1696 1697
    for (k=0; k<N_ZC; k++) {
      // 420 is the multiplicative inverse of 2 (required since ru is exp[j 2\pi n])
      X_u[i][k] = ((uint32_t*)ru)[(((k*(1+(inv_u*k)))%N_ZC)*420)%N_ZC];
      //        printf("X_u[%d][%d] (%d)(%d)(%d) : %d,%d\n",i,k,u*inv_u*k*(1+(inv_u*k)),u*inv_u*k*(1+(inv_u*k))/2,(u*inv_u*k*(1+(inv_u*k))/2)%N_ZC,((int16_t*)&X_u[i][k])[0],((int16_t*)&X_u[i][k])[1]);
1698 1699
    }
  }
1700

1701
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_OUT);
1702 1703

}