prach.c 64.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

22 23 24 25 26 27 28 29 30 31
/*! \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
 */
32
#include "PHY/sse_intrin.h"
33 34 35
#include "PHY/defs.h"
#include "PHY/extern.h"
//#include "prach.h"
36
#include "PHY/LTE_TRANSPORT/if4_tools.h"
37 38 39 40
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "UTIL/LOG/vcd_signal_dumper.h"

Raymond Knopp's avatar
 
Raymond Knopp committed
41
//#define PRACH_DEBUG 1
42

43 44 45
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};
46

47 48 49
int16_t ru[2*839]; // quantized roots of unity
uint32_t ZC_inv[839]; // multiplicative inverse for roots u
uint16_t du[838];
50 51

typedef struct {
52 53 54 55
  uint8_t f_ra;
  uint8_t t0_ra;
  uint8_t t1_ra;
  uint8_t t2_ra;
56 57
} PRACH_TDD_PREAMBLE_MAP_elem;
typedef struct {
58
  uint8_t num_prach;
59 60 61 62
  PRACH_TDD_PREAMBLE_MAP_elem map[6];
} PRACH_TDD_PREAMBLE_MAP;

// This is table 5.7.1-4 from 36.211
63
PRACH_TDD_PREAMBLE_MAP tdd_preamble_map[64][7] = {
64 65 66 67 68 69 70 71 72 73 74
  // 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
75
  { {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}}}},
76 77 78
  // 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
79
  { {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}}}},
80 81 82 83 84 85 86
  // 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
87
  { {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}}}},
88
  // TDD Configuration Index 12
89
  { {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}}},
90 91 92 93 94 95 96
    {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
97
  { {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}}},
98 99 100 101 102 103 104
    {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
105
  { {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}}},
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,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
113
  { {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}}},
114 115 116 117 118
    {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
119
  { {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}}},
120 121 122 123 124
    {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
125
  { {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}}},
126 127 128 129 130
    {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
131
  { {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}}},
132 133 134 135 136 137 138 139
    {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
140
  { {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}}},
141 142 143 144 145 146 147 148
    {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
149
  { {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}}}},
150
  // TDD Configuration Index 21
151 152
  { {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}}}},

153
  // TDD Configuration Index 22
154 155
  { {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}}}},

156
  // TDD Configuration Index 23
157 158
  { {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}}}},

159
  // TDD Configuration Index 24
160 161 162 163 164
  { {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}}}},

165
  // TDD Configuration Index 26
166 167
  { {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}}}},

168
  // TDD Configuration Index 27
169
  { {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}}},
170 171 172 173 174 175 176 177
    {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
178
  { {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}}},
179 180 181 182
    {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}}}
  },
183

184
  // TDD Configuration Index 29
185
  { {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}}},
186 187 188 189 190 191 192
    {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}}}
  },
193 194


195
  // TDD Configuration Index 30
196 197
  { {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}}}},

198
  // TDD Configuration Index 31
199 200
  { {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}}}},

201
  // TDD Configuration Index 32
202 203
  { {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}}}},

204
  // TDD Configuration Index 33
205 206
  { {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}}}},

207
  // TDD Configuration Index 34
208 209
  { {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}}}},

210
  // TDD Configuration Index 35
211 212
  { {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}}}},

213
  // TDD Configuration Index 36
214 215
  { {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}}}},

216
  // TDD Configuration Index 37
217
  { {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}}},
218 219 220 221 222 223 224 225
    {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
226
  { {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}}},
227 228 229 230
    {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}}}
  },
231

232
  // TDD Configuration Index 39
233
  { {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}}},
234 235 236 237 238 239 240 241 242
    {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
243
  { {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}}}},
244
  // TDD Configuration Index 41
245 246
  { {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}}}},

247
  // TDD Configuration Index 42
248 249
  { {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}}}},

250
  // TDD Configuration Index 43
251 252
  { {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}}}},

253
  // TDD Configuration Index 44
254 255
  { {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}}}},

256
  // TDD Configuration Index 45
257 258
  { {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}}}},

259
  // TDD Configuration Index 46
260 261
  { {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}}}},

262
  // TDD Configuration Index 47
263
  { {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}}},
264 265 266 267 268 269
    {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}}}
  }
270 271
};

272 273


274
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,
275 276 277 278 279 280 281 282 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
                                             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
                                           };
334

335
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,
336 337 338 339 340 341 342
                                            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
                                         };
343 344

#ifdef USER_MODE
345 346
void dump_prach_config(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe)
{
347 348 349 350 351 352 353

  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");
354

355
  if(frame_parms->frame_type==1) fprintf(fd,"prach_config: tdd_config        = %d\n",frame_parms->tdd_config);
356 357 358

  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);
359 360 361 362 363 364 365 366 367
  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
368 369
void fill_du(uint8_t prach_fmt)
{
370

371 372 373
  uint16_t iu,u,p;
  uint16_t N_ZC;
  uint16_t *prach_root_sequence_map;
374 375 376 377

  if (prach_fmt<4) {
    N_ZC = 839;
    prach_root_sequence_map = prach_root_sequence_map0_3;
378
  } else {
379 380 381 382
    N_ZC = 139;
    prach_root_sequence_map = prach_root_sequence_map4;
  }

383
  for (iu=0; iu<(N_ZC-1); iu++) {
384 385 386

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

388 389
    while (((u*p)%N_ZC)!=1)
      p++;
390

391 392
    du[u] = ((p<(N_ZC>>1)) ? p : (N_ZC-p));
  }
393

394 395
}

396 397
uint8_t get_num_prach_tdd(LTE_DL_FRAME_PARMS *frame_parms)
{
398 399 400 401

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

402 403
uint8_t get_fid_prach_tdd(LTE_DL_FRAME_PARMS *frame_parms,uint8_t tdd_map_index)
{
404 405 406 407

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

408 409
uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type)
{
410 411 412 413 414 415 416

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

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

418 419
    if (prach_ConfigIndex < 30)
      return (1);
420

421 422
    if (prach_ConfigIndex < 40)
      return (2);
423

424 425 426 427 428 429 430
    if (prach_ConfigIndex < 48)
      return (3);
    else
      return (4);
  }
}

431 432 433 434 435 436 437 438 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
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);
}
476

477 478
int is_prach_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t subframe)
{
479

480 481
  uint8_t prach_ConfigIndex  = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
  uint8_t tdd_config         = frame_parms->tdd_config;
482 483 484
  uint8_t t0_ra;
  uint8_t t1_ra;
  uint8_t t2_ra;
485

Raymond Knopp's avatar
 
Raymond Knopp committed
486

487 488 489
  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)) ||
490
        (((frame&1) == 0) && (subframe == 9)))  // This is an odd frame, ignore even-only PRACH frames
491
      if (((prach_ConfigIndex&0xf)<3) || // 0,1,2,16,17,18,32,33,34,48,49,50
492 493 494
          ((prach_ConfigIndex&0x1f)==18) || // 18,50
          ((prach_ConfigIndex&0xf)==15))   // 15,47
        return(0);
495 496 497 498 499 500

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

502 503 504 505
    case 1:
    case 4:
      return(subframe==4);
      break;
506

507 508 509 510
    case 2:
    case 5:
      return(subframe==7);
      break;
511

512 513 514
    case 6:
      return((subframe==1) || (subframe==6));
      break;
515

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

520 521 522
    case 8:
      return((subframe==3) || (subframe==8));
      break;
523

524 525 526
    case 9:
      return((subframe==1) || (subframe==4) || (subframe==7));
      break;
527

528 529 530
    case 10:
      return((subframe==2) || (subframe==5) || (subframe==8));
      break;
531

532 533 534
    case 11:
      return((subframe==3) || (subframe==6) || (subframe==9));
      break;
535

536 537 538
    case 12:
      return((subframe&1)==0);
      break;
539

540 541 542
    case 13:
      return((subframe&1)==1);
      break;
543

544 545 546
    case 14:
      return(1==1);
      break;
547

548 549 550 551
    case 15:
      return(subframe==9);
      break;
    }
552
  } else { // TDD
553 554 555 556 557 558 559 560 561

    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);
562
    }
563 564 565 566

    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;
567
#ifdef PRACH_DEBUG
568
    LOG_D(PHY,"[PRACH] Checking for PRACH format (ConfigIndex %d) in TDD subframe %d (%d,%d,%d)\n",
569 570 571 572 573
          prach_ConfigIndex,
          subframe,
          t0_ra,t1_ra,t2_ra);
#endif

574
    if ((((t0_ra == 1) && ((frame &1)==0))||  // frame is even and PRACH is in even frames
575 576 577 578 579 580
         ((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));
581
      else                                               // PRACH can be in UpPTS
582 583
        return((((subframe%5)-1)==t2_ra));
    } else
584 585
      return(1==2);
  }
586

587 588 589 590
  // shouldn't get here!
  return(2==1);
}

591
int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t Nf )
592 593
{

594 595 596 597 598 599 600 601 602 603
  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;
604
  static int16_t prach_tmp[45600*2] __attribute__((aligned(32)));
605
  int16_t *prach            = prach_tmp;
606
  int16_t *prach2;
607
  int16_t amp               = ue->prach_vars[eNB_id]->amp;
608 609 610 611 612 613
  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;
614
  uint16_t d_start,numshift;
615 616

  uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
617 618
  //uint8_t Nsp=2;
  //uint8_t f_ra,t1_ra;
619 620
  uint16_t N_ZC = (prach_fmt<4)?839:139;
  uint8_t not_found;
621
  int k;
622 623 624 625
  int16_t *Xu;
  uint16_t u;
  int32_t Xu_re,Xu_im;
  uint16_t offset,offset2;
626 627
  int prach_start;
  int i, prach_len;
628
  uint16_t first_nonzero_root_idx=0;
629

Raymond Knopp's avatar
 
Raymond Knopp committed
630
#if defined(EXMIMO) || defined(OAI_USRP)
631
  prach_start =  (ue->rx_offset+subframe*ue->frame_parms.samples_per_tti-ue->hw_timing_advance-ue->N_TA_offset);
632 633 634 635 636 637 638
#ifdef PRACH_DEBUG
    LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id,
        prach_start,
        ue->rx_offset,
        ue->hw_timing_advance,
        ue->N_TA_offset);
#endif
639

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

643 644
  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);
645

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

650

651 652
  // First compute physical root sequence
  if (restricted_set == 0) {
653 654
    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
655
      mac_xface->macphy_exit("PRACH: Illegal Ncs_config for unrestricted format");
656
      return 0; // not reached
657
    }
658 659 660

    NCS = NCS_unrestricted[Ncs_config];
  } else {
661 662
    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
663
      mac_xface->macphy_exit("PRACH: Illegal Ncs_config for restricted format");
664
      return 0; // not reached
665
    }
666

667 668 669
    NCS = NCS_restricted[Ncs_config];
  }

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

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

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

    // 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;
683

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

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

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

  // 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)));
707

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

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

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

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

736
      u = prach_root_sequence_map[index];
737

738
      uint16_t n_group_ra = 0;
739

740
      if ( (du[u]<(N_ZC/3)) && (du[u]>=NCS) ) {
741 742 743 744 745 746 747 748 749 750 751 752
        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;
753
      }
754

755 756 757 758
      // 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)
759
        first_nonzero_root_idx = preamble_offset;
760 761

      if (preamble_index0 < numshift) {
762 763 764 765 766 767
        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;
768 769 770
      }
    }
  }
771

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

775 776
  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",
777 778 779
          rootSequenceIndex,preamble_index,NCS,Ncs_config,N_ZC/NCS,n_ra_prb,
          preamble_offset,preamble_shift);

780 781 782 783
#endif

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

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

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

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

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

  /*
796 797 798
    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);
799 800
  */
  k*=2;
801

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

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

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

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

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

823
  case 100:
824 825 826 827
    if (ue->frame_parms.threequarter_fs == 0)
      memset((void*)prachF,0,4*24576);
    else
      memset((void*)prachF,0,4*18432);
828 829 830
    break;
  }

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

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

836 837
    Xu_re = (((int32_t)Xu[offset<<1]*amp)>>15);
    Xu_im = (((int32_t)Xu[1+(offset<<1)]*amp)>>15);
838 839 840
    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;

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

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

850 851 852 853
  case 1:
  case 3:
    Ncp = 21024;
    break;
854

855 856 857
  case 2:
    Ncp = 6240;
    break;
858

859 860 861
  case 4:
    Ncp = 448;
    break;
862

863 864 865 866 867
  default:
    Ncp = 3168;
    break;
  }

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

874 875 876
  case 15:
    Ncp>>=3;
    break;
877

878 879 880
  case 25:
    Ncp>>=2;
    break;
881

882 883 884
  case 50:
    Ncp>>=1;
    break;
885

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

891 892 893
  if (ue->frame_parms.threequarter_fs == 1)
    Ncp=(Ncp*3)>>2;

894
  prach2 = prach+(Ncp<<1);
895

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

908
      if (prach_fmt>1) {
909
        memmove( prach2+3072, prach2, 6144 );
910
        prach_len = 2*1536+Ncp;
911 912
      }
    }
913

914
    break;
915

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

927
      if (prach_fmt>1) {
928
        memmove( prach2+6144, prach2, 12288 );
929
        prach_len = 2*3072+Ncp;
930 931
      }
    }
932

933
    break;
934

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

      if (prach_fmt>1) {
949
        memmove( prach2+12288, prach2, 24576 );
950
        prach_len = 2*6144+Ncp;
951 952
      }
    }
953

954
    break;
955

956 957
  case 50:
    if (prach_fmt == 4) {
958
      idft2048(prachF,prach2,1);
959
      memmove( prach, prach+4096, Ncp<<2 );
960
      prach_len = 2048+Ncp;
961
    } else {
962
      idft12288(prachF,prach2);
963
      memmove( prach, prach+24576, Ncp<<2 );
964
      prach_len = 12288+Ncp;
965

966
      if (prach_fmt>1) {
967
        memmove( prach2+24576, prach2, 49152 );
968
        prach_len = 2*12288+Ncp;
969 970
      }
    }
971

972
    break;
973

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

985
      if (prach_fmt>1) {
986
        memmove( prach2+36834, prach2, 73728 );
987
        prach_len = 2*18432+Ncp;
988 989
      }
    }
990

991
    break;
992

993
  case 100:
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    if (ue->frame_parms.threequarter_fs == 0) { 
      if (prach_fmt == 4) {
	idft4096(prachF,prach2,1);
	memmove( prach, prach+8192, Ncp<<2 );
	prach_len = 4096+Ncp;
      } else {
	idft24576(prachF,prach2);
	memmove( prach, prach+49152, Ncp<<2 );
	prach_len = 24576+Ncp;
	
	if (prach_fmt>1) {
	  memmove( prach2+49152, prach2, 98304 );
	  prach_len = 2* 24576+Ncp;
	}
1008
      }
1009
    }
1010
    else {
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
      if (prach_fmt == 4) {
	idft3072(prachF,prach2);
	//TODO: account for repeated format in dft output
	memmove( prach, prach+6144, Ncp<<2 );
	prach_len = 3072+Ncp;
      } else {
	idft18432(prachF,prach2);
	memmove( prach, prach+36864, Ncp<<2 );
	prach_len = 18432+Ncp;
	printf("Generated prach for 100 PRB, 3/4 sampling\n");
	if (prach_fmt>1) {
	  memmove( prach2+36834, prach2, 73728 );
	  prach_len = 2*18432+Ncp;
	}
      } 
1026
    }
1027

1028 1029 1030 1031
    break;
  }

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

1033
  if (prach_fmt==4) {
1034
    LOG_E( PHY, "prach_fmt4 not fully implemented" );
Lionel Gauthier's avatar
Lionel Gauthier committed
1035
    mac_xface->macphy_exit("prach_fmt4 not fully implemented");
1036
    return 0; // not reached
1037
  } else {
1038
#if defined(EXMIMO) || defined(OAI_USRP)
1039
    int j;
1040
    int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*ue->frame_parms.samples_per_tti;
1041
    LOG_D( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow );
1042

1043 1044 1045
    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;
1046
    }
1047 1048

    for (i=0; i<overflow; i++,j++) {
1049 1050
      ((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;
1051
    }
1052
#if defined(EXMIMO)
1053 1054 1055 1056 1057 1058 1059 1060 1061
    // handle switch before 1st TX subframe, guarantee that the slot prior to transmission is switch on
    for (k=prach_start - (ue->frame_parms.samples_per_tti>>1) ; k<prach_start ; k++) {
      if (k<0)
	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;
      else
	ue->common_vars.txdata[0][k] &= 0xFFFEFFFE;
    }
1062
#endif
1063
#else
1064
    
1065
    for (i=0; i<prach_len; i++) {
1066 1067
      ((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];
1068
    }
1069

1070 1071
#endif
  }
1072

1073 1074 1075 1076 1077 1078

#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

1079
  return signal_energy( (int*)prach, 256 );
1080
}
1081
//__m128i mmtmpX0,mmtmpX1,mmtmpX2,mmtmpX3;
1082

1083
void rx_prach(PHY_VARS_eNB *eNB,
1084 1085 1086 1087
	      uint16_t *preamble_energy_list, 
	      uint16_t *preamble_delay_list, 
	      uint16_t Nf, 
	      uint8_t tdd_mapindex)
1088
{
1089 1090

  int i;
1091
  lte_frame_type_t frame_type = eNB->frame_parms.frame_type;
Raymond Knopp's avatar
Raymond Knopp committed
1092
  int subframe                = eNB->proc.subframe_prach;
1093 1094 1095 1096 1097 1098 1099 1100
  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];
1101 1102 1103 1104 1105 1106 1107 1108
  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;
1109
  uint16_t d_start=0;
1110 1111 1112 1113 1114
  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;
1115
  int k;
1116 1117 1118 1119
  uint16_t u;
  int16_t *Xu;
  uint16_t offset;
  int16_t Ncp;
1120
  uint16_t first_nonzero_root_idx=0;
1121 1122 1123
  uint8_t new_dft=0;
  uint8_t aa;
  int32_t lev;
Raymond Knopp's avatar
 
Raymond Knopp committed
1124
  int16_t levdB;
1125
  int fft_size,log2_ifft_size;
1126
  uint8_t nb_ant_rx = 1; //eNB->frame_parms.nb_antennas_rx;
1127

1128
  //  int en;
1129 1130

  for (aa=0; aa<nb_ant_rx; aa++) {
1131
    prach[aa] = (int16_t*)&eNB->common_vars.rxdata[0][aa][subframe*eNB->frame_parms.samples_per_tti-eNB->N_TA_offset];
1132
  }
1133

1134 1135 1136 1137
  // 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
1138
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for unrestricted format");
1139
      return; // not reached
1140
    }
1141 1142 1143

    NCS = NCS_unrestricted[Ncs_config];
  } else {
1144 1145
    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
1146
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for restricted format");
1147
      return; // not reached
1148
    }
1149

1150 1151 1152
    NCS = NCS_restricted[Ncs_config];
  }

1153
  start_meas(&eNB->rx_prach);
1154

1155
  n_ra_prb = get_prach_prb_offset(&(eNB->frame_parms),tdd_mapindex,Nf);
1156
  prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
1157

1158 1159 1160
  // 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);
1161

1162
  if (NCS2==0)
1163
    NCS2 = N_ZC;
1164 1165 1166 1167

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

1170 1171 1172 1173
  case 1:
  case 3:
    Ncp = 21024;
    break;
1174

1175 1176 1177
  case 2:
    Ncp = 6240;
    break;
1178

1179 1180 1181
  case 4:
    Ncp = 448;
    break;
1182

1183 1184 1185 1186
  default:
    Ncp = 3168;
    break;
  }
1187

1188
  // Adjust CP length based on UL bandwidth
1189
  switch (eNB->frame_parms.N_RB_UL) {
1190 1191 1192
  case 6:
    Ncp>>=4;
    break;
1193

1194 1195 1196
  case 15:
    Ncp>>=3;
    break;
1197

1198 1199 1200
  case 25:
    Ncp>>=2;
    break;
1201

1202 1203 1204
  case 50:
    Ncp>>=1;
    break;
1205

1206 1207 1208
  case 75:
    Ncp=(Ncp*3)>>2;
    break;
1209 1210 1211 1212 1213

  case 100:
    if (eNB->frame_parms.threequarter_fs == 1)
      Ncp=(Ncp*3)>>2;
    break;
1214 1215
  }

1216 1217

  if ((eNB->node_function == eNodeB_3GPP) ||
1218
      (eNB->node_function == eNodeB_3GPP_BBU) ||
1219
      (eNB->node_function == NGFI_RRU_IF4p5)) { // compute the DFTs of the PRACH temporal resources
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 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
    // 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:
1291 1292 1293 1294 1295 1296 1297 1298 1299
	if (eNB->frame_parms.threequarter_fs==0) {
	  if (prach_fmt == 4) {
	    dft4096(prach2,rxsigF[aa],1);
	  } else {
	    dft24576(prach2,rxsigF[aa]);
	    
	    if (prach_fmt>1)
	      dft24576(prach2+49152,rxsigF[aa]+49152);
	  }
1300
	} else {
1301 1302 1303 1304 1305 1306 1307 1308
	  if (prach_fmt == 4) {
	    dft3072(prach2,rxsigF[aa]);
	  } else {
	    dft18432(prach2,rxsigF[aa]);
	    
	    if (prach_fmt>1)
	      dft18432(prach2+36864,rxsigF[aa]+36864);
	  }
1309 1310 1311 1312 1313 1314 1315
	}
	
	break;
      }
    }
  }

1316
  if (eNB->node_function == NGFI_RRU_IF4p5) {
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
    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 **** ///    
Raymond Knopp's avatar
Raymond Knopp committed
1328
    send_IF4p5(eNB, eNB->proc.frame_prach, eNB->proc.subframe_prach, IF4p5_PRACH, k);
1329

Raymond Knopp's avatar
Raymond Knopp committed
1330 1331 1332
    //    en = dB_fixed(signal_energy(&rxsigF[0][k],840));
    //    if (en>60)
    //      printf("PRACH: Frame %d, Subframe %d => %d dB\n",eNB->proc.frame_rx,eNB->proc.subframe_rx,en);
1333
    return;
1334
  } else if (eNB->node_function == NGFI_RCC_IF4p5) {
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
    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]),
1348 1349 1350 1351 1352 1353
            839*2*sizeof(int16_t));

    //en = dB_fixed(signal_energy(&rxsigF[0][k],840));
    //    if (en>60)
    //printf("PRACH: Frame %d, Subframe %d => %d dB\n",eNB->proc.frame_rx,eNB->proc.subframe_rx,en);

1354
  }
1355
  
1356
  // in case of RCC and prach received rx_thread wakes up prach
1357

1358
  // here onwards is for eNodeB_3GPP or NGFI_RCC_IF4p5
1359

1360 1361
  preamble_offset_old = 99;

1362 1363
  for (preamble_index=0 ; preamble_index<64 ; preamble_index++) {
    if (restricted_set == 0) {
1364 1365
      // 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)));
1366
      
1367
      if (preamble_offset != preamble_offset_old) {
1368 1369 1370 1371
        preamble_offset_old = preamble_offset;
        new_dft = 1;
        // This is the \nu corresponding to the preamble index
        preamble_shift  = 0;
1372
      }
1373
      
1374
      else {
1375
        preamble_shift  -= NCS;
1376
	
1377 1378
        if (preamble_shift < 0)
          preamble_shift+=N_ZC;
1379
      }
1380
    } else { // This is the high-speed case
1381
      new_dft = 0;
1382

1383 1384 1385 1386
      // 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) {
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
        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
1398
            DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
1399 1400
          } else {
            // prach_root_sequence_map points to prach_root_sequence_map4
1401
            DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
1402 1403 1404 1405
          }

          u = prach_root_sequence_map[index];

1406
          uint16_t n_group_ra = 0;
1407

1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
          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++);
        }
1428
      }
1429 1430 1431

      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)
1432
      else
1433
        preamble_shift = 0;
1434

1435 1436
      if (preamble_shift < 0)
        preamble_shift+=N_ZC;
1437

1438
      preamble_index0++;
1439

1440
      if (preamble_index == 0)
1441
        first_nonzero_root_idx = preamble_offset;
1442
    }
1443

1444 1445 1446 1447 1448 1449
    // 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;
1450

1451 1452
    if (new_dft == 1) {
      new_dft = 0;
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
      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 );
1475
#ifdef PRACH_DEBUG
1476
      write_output("prach_rx0.m","prach_rx0",prach[0],6144+792,1,1);
1477
#endif
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
      // 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;
	}
1518
#ifdef PRACH_DEBUG
1519
	if (aa==0) write_output("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
1520
#endif
1521
      // if (aa=1) write_output("prach_rxF_comp1.m","prach_rxF_comp1",prachF,1024,1,1);
1522
      }// antennas_rx
Raymond Knopp's avatar
Raymond Knopp committed
1523

1524
#ifdef PRACH_DEBUG
1525

1526
      //      if (en>40) {
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
	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;
	printf("Dumping prach, k = %d (n_ra_prb %d)\n",k,n_ra_prb);
	write_output("rxsigF.m","prach_rxF",&rxsigF[0][k],840,1,1);
	write_output("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
	write_output("prach_ifft0.m","prach_t0",prach_ifft[0],1024,1,1);
Raymond Knopp's avatar
Raymond Knopp committed
1539
	exit(-1);
1540
	//      }
1541
#endif
1542
    } // new dft
1543
    
1544 1545 1546
    // 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;
1547
    
1548
    for (i=0; i<NCS2; i++) {
1549
      lev = 0;
1550
      
1551
      for (aa=0; aa<nb_ant_rx; aa++) {
1552
	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)];
1553
      }
1554
      
1555
      levdB = dB_fixed_times10(lev);
1556
      
1557
      if (levdB>preamble_energy_list[preamble_index] ) {
1558 1559
	preamble_energy_list[preamble_index]  = levdB;
	preamble_delay_list[preamble_index]   = (i*fft_size)>>log2_ifft_size;
1560
      }
1561
    }
1562
    
1563
#ifdef PRACH_DEBUG
1564
    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,
1565
	  preamble_shift, NCS2,NCS,Ncp);
1566 1567 1568
#endif
    //  exit(-1);
  }// preamble_index
1569 1570 1571
  
  stop_meas(&eNB->rx_prach);
  
1572 1573
}

1574 1575
void init_prach_tables(int N_ZC)
{
1576 1577 1578 1579 1580 1581

  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;
1582 1583 1584

  for (i=2; i<N_ZC; i++) {
    for (m=2; m<N_ZC; m++)
1585
      if (((i*m)%N_ZC) == 1) {
1586 1587
        ZC_inv[i] = m;
        break;
1588
      }
1589

1590
#ifdef PRACH_DEBUG
1591

1592 1593
    if (i<16)
      printf("i %d : inv %d\n",i,ZC_inv[i]);
1594

1595 1596 1597 1598
#endif
  }

  // Compute quantized roots of unity
1599 1600 1601
  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)));
1602
#ifdef PRACH_DEBUG
1603

1604 1605
    if (i<16)
      printf("i %d : runity %d,%d\n",i,ru[i<<1],ru[1+(i<<1)]);
1606

1607 1608 1609 1610 1611
#endif
  }
}

void compute_prach_seq(PRACH_CONFIG_COMMON *prach_config_common,
1612 1613 1614
                       lte_frame_type_t frame_type,
                       uint32_t X_u[64][839])
{
1615 1616 1617 1618

  // 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;
1619
  uint8_t prach_fmt = get_prach_fmt(prach_config_common->prach_ConfigInfo.prach_ConfigIndex,frame_type);
1620 1621
  uint16_t *prach_root_sequence_map;
  uint16_t u, preamble_offset;
1622
  uint16_t n_shift_ra,n_shift_ra_bar, d_start,numshift;
1623
  uint8_t not_found;
1624

1625
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_IN);
1626 1627 1628 1629 1630 1631

#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) {
1632
    LOG_E( PHY, "PRACH sequence is only precomputed for prach_fmt<4 (have %"PRIu8")\n", prach_fmt );
Lionel Gauthier's avatar
Lionel Gauthier committed
1633
    mac_xface->macphy_exit("PRACH sequence is only precomputed for prach_fmt<4");
1634
    return; // not reached
1635 1636 1637 1638 1639
  }

  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

1640 1641 1642 1643 1644 1645
  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;
  }
1646 1647 1648


#ifdef PRACH_DEBUG
1649
  LOG_I( PHY, "compute_prach_seq: done init prach_tables\n" );
1650 1651
#endif

1652
  if (prach_config_common->prach_ConfigInfo.highSpeedFlag== 0) {
1653

1654 1655 1656
#ifdef PRACH_DEBUG
    LOG_I(PHY,"Low speed prach : NCS_config %d\n",prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig);
#endif
1657

1658
    if (prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig>15) {
1659
      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
1660
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for unrestricted format");
1661
      return; // not reached
1662
    } else {
1663 1664
      NCS = NCS_unrestricted[prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig];
    }
1665

1666
    num_preambles = (NCS==0) ? 64 : ((64*NCS)/N_ZC);
1667

1668
    if (NCS>0) num_preambles++;
1669

1670
    preamble_offset = 0;
1671 1672
  } else {

1673
#ifdef PRACH_DEBUG
1674
    LOG_I( PHY, "high speed prach : NCS_config %"PRIu8"\n", prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig );
1675
#endif
1676

1677
    if (prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig>14) {
1678
      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
1679
      mac_xface->macphy_exit("PRACH Illegal Ncs_config for restricted format");
1680
      return; // not reached
1681
    } else {
1682 1683 1684
      NCS = NCS_restricted[prach_config_common->prach_ConfigInfo.zeroCorrelationZoneConfig];
      fill_du(prach_fmt);
    }
1685

1686 1687 1688 1689
    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;
1690

1691
    while (not_found == 1) {
1692
      // current root depending on rootSequenceIndex
1693
      int index = (prach_config_common->rootSequenceIndex + preamble_offset) % N_ZC;
1694

1695
      if (prach_fmt<4) {
1696
        // prach_root_sequence_map points to prach_root_sequence_map0_3
1697
        DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
1698
      } else {
1699
        // prach_root_sequence_map points to prach_root_sequence_map4
1700
        DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
1701
      }
1702

1703
      u = prach_root_sequence_map[index];
1704

1705
      uint16_t n_group_ra = 0;
1706

1707
      if ( (du[u]<(N_ZC/3)) && (du[u]>=NCS) ) {
1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
        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;
1720
      }
1721

1722 1723
      // This is the number of cyclic shifts for the current root u
      numshift = (n_shift_ra*n_group_ra) + n_shift_ra_bar;
1724

1725
      // skip to next root and recompute parameters if numshift==0
1726 1727 1728 1729
      if (numshift>0)
        not_found = 0;
      else
        preamble_offset++;
1730 1731 1732 1733
    }
  }

#ifdef PRACH_DEBUG
1734

1735
  if (NCS>0)
1736 1737
    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 );
1738

1739 1740
#endif

1741
  for (i=0; i<num_preambles; i++) {
1742
    int index = (prach_config_common->rootSequenceIndex+i+preamble_offset) % N_ZC;
1743

1744
    if (prach_fmt<4) {
1745
      // prach_root_sequence_map points to prach_root_sequence_map0_3
1746
      DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
1747
    } else {
1748
      // prach_root_sequence_map points to prach_root_sequence_map4
1749
      DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
1750
    }
1751

1752
    u = prach_root_sequence_map[index];
1753

1754
    inv_u = ZC_inv[u]; // multiplicative inverse of u
1755

1756 1757 1758 1759

    // 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

1760 1761 1762 1763
    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]);
1764 1765
    }
  }
1766

1767
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_OUT);
1768 1769

}