- Remove all files referencing EXMIMO - Remove all targets/variables/defines that seem to be related to EXMIMO
494 lines
15 KiB
C
494 lines
15 KiB
C
/*
|
|
* 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.1 (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
|
|
*/
|
|
|
|
/*! \file PHY/LTE_TRANSPORT/prach_ue.c
|
|
* \brief Top-level routines for 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
|
|
*/
|
|
#include "PHY/sse_intrin.h"
|
|
#include "PHY/defs_UE.h"
|
|
#include "targets/RT/USER/lte-softmodem.h"
|
|
#include "PHY/phy_extern_ue.h"
|
|
//#include "prach.h"
|
|
#include "PHY/LTE_TRANSPORT/if4_tools.h"
|
|
|
|
#include "SCHED_UE/sched_UE.h"
|
|
#include "SCHED/sched_common_extern.h"
|
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
|
|
|
#include "../LTE_TRANSPORT/prach_extern.h"
|
|
#include "common/utils/lte/prach_utils.h"
|
|
|
|
//#define PRACH_DEBUG 1
|
|
|
|
int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t Nf ) {
|
|
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;
|
|
static int16_t prach_tmp[45600*4] __attribute__((aligned(32)));
|
|
int16_t *prach = prach_tmp;
|
|
int16_t *prach2;
|
|
int16_t amp = ue->prach_vars[eNB_id]->amp;
|
|
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;
|
|
uint16_t d_start=-1,numshift;
|
|
uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
|
|
//uint8_t Nsp=2;
|
|
//uint8_t f_ra,t1_ra;
|
|
uint16_t N_ZC = (prach_fmt<4)?839:139;
|
|
uint8_t not_found;
|
|
int k;
|
|
int16_t *Xu;
|
|
uint16_t u;
|
|
int32_t Xu_re,Xu_im;
|
|
uint16_t offset,offset2;
|
|
int prach_start;
|
|
int i, prach_len;
|
|
uint16_t first_nonzero_root_idx=0;
|
|
|
|
prach_start = (ue->rx_offset+subframe*ue->frame_parms.samples_per_tti-ue->hw_timing_advance-ue->N_TA_offset);
|
|
#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
|
|
|
|
if (prach_start<0)
|
|
prach_start+=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
|
|
|
|
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);
|
|
|
|
// First compute physical root sequence
|
|
if (restricted_set == 0) {
|
|
AssertFatal(Ncs_config <= 15,
|
|
"[PHY] FATAL, Illegal Ncs_config for unrestricted format %"PRIu8"\n", Ncs_config );
|
|
NCS = NCS_unrestricted[Ncs_config];
|
|
} else {
|
|
AssertFatal(Ncs_config <= 14,
|
|
"[PHY] FATAL, Illegal Ncs_config for restricted format %"PRIu8"\n", Ncs_config );
|
|
NCS = NCS_restricted[Ncs_config];
|
|
}
|
|
|
|
n_ra_prb = get_prach_prb_offset(ue->frame_parms.frame_type,
|
|
ue->frame_parms.tdd_config,
|
|
ue->frame_parms.N_RB_UL,
|
|
ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex,
|
|
ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset,
|
|
tdd_mapindex, Nf);
|
|
prach_root_sequence_map = (prach_fmt<4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
|
|
/*
|
|
// this code is not part of get_prach_prb_offset
|
|
if (frame_type == TDD) { // TDD
|
|
|
|
if (tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach==0) {
|
|
LOG_E( PHY, "[PHY][UE %"PRIu8"] Illegal prach_ConfigIndex %"PRIu8" for ", ue->Mod_id, prach_ConfigIndex );
|
|
}
|
|
|
|
// 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 = ue->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 = ue->frame_parms.N_RB_UL - 6*(f_ra+1);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
// 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)));
|
|
|
|
if (restricted_set == 0) {
|
|
// This is the \nu corresponding to the preamble index
|
|
preamble_shift = (NCS==0)? 0 : (preamble_index % (N_ZC/NCS));
|
|
preamble_shift *= NCS;
|
|
} else { // This is the high-speed case
|
|
#ifdef PRACH_DEBUG
|
|
LOG_I(PHY,"[UE %d] High-speed mode, NCS_config %d\n",ue->Mod_id,Ncs_config);
|
|
#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;
|
|
|
|
while (not_found == 1) {
|
|
// current root depending on rootSequenceIndex and preamble_offset
|
|
int index = (rootSequenceIndex + preamble_offset) % N_ZC;
|
|
|
|
if (prach_fmt<4) {
|
|
// prach_root_sequence_map points to prach_root_sequence_map0_3
|
|
DevAssert( index < sizeof(prach_root_sequence_map0_3) / sizeof(prach_root_sequence_map0_3[0]) );
|
|
} else {
|
|
// prach_root_sequence_map points to prach_root_sequence_map4
|
|
DevAssert( index < sizeof(prach_root_sequence_map4) / sizeof(prach_root_sequence_map4[0]) );
|
|
}
|
|
|
|
u = prach_root_sequence_map[index];
|
|
uint16_t n_group_ra = 0;
|
|
|
|
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;
|
|
|
|
if (numshift>0 && preamble_index0==preamble_index)
|
|
first_nonzero_root_idx = preamble_offset;
|
|
|
|
if (preamble_index0 < numshift) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now generate PRACH signal
|
|
#ifdef PRACH_DEBUG
|
|
|
|
if (NCS>0)
|
|
LOG_I(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",
|
|
rootSequenceIndex,preamble_index,NCS,Ncs_config,N_ZC/NCS,n_ra_prb,
|
|
preamble_offset,preamble_shift);
|
|
|
|
#endif
|
|
// nsymb = (frame_parms->Ncp==0) ? 14:12;
|
|
// subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*subframe*nsymb;
|
|
k = (12*n_ra_prb) - 6*ue->frame_parms.N_RB_UL;
|
|
|
|
if (k<0)
|
|
k+=ue->frame_parms.ofdm_symbol_size;
|
|
|
|
k*=12;
|
|
k+=13;
|
|
Xu = (int16_t *)ue->X_u[preamble_offset-first_nonzero_root_idx];
|
|
/*
|
|
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);
|
|
*/
|
|
k*=2;
|
|
|
|
switch (ue->frame_parms.N_RB_UL) {
|
|
case 6:
|
|
memset((void *)prachF,0,4*1536);
|
|
break;
|
|
|
|
case 15:
|
|
memset((void *)prachF,0,4*3072);
|
|
break;
|
|
|
|
case 25:
|
|
memset((void *)prachF,0,4*6144);
|
|
break;
|
|
|
|
case 50:
|
|
memset((void *)prachF,0,4*12288);
|
|
break;
|
|
|
|
case 75:
|
|
memset((void *)prachF,0,4*18432);
|
|
break;
|
|
|
|
case 100:
|
|
if (ue->frame_parms.threequarter_fs == 0)
|
|
memset((void *)prachF,0,4*24576);
|
|
else
|
|
memset((void *)prachF,0,4*18432);
|
|
|
|
break;
|
|
}
|
|
|
|
for (offset=0,offset2=0; offset<N_ZC; offset++,offset2+=preamble_shift) {
|
|
if (offset2 >= N_ZC)
|
|
offset2 -= N_ZC;
|
|
|
|
Xu_re = (((int32_t)Xu[offset<<1]*amp)>>15);
|
|
Xu_im = (((int32_t)Xu[1+(offset<<1)]*amp)>>15);
|
|
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;
|
|
|
|
if (k==(12*2*ue->frame_parms.ofdm_symbol_size))
|
|
k=0;
|
|
}
|
|
|
|
switch (prach_fmt) {
|
|
case 0:
|
|
Ncp = 3168;
|
|
break;
|
|
|
|
case 1:
|
|
case 3:
|
|
Ncp = 21024;
|
|
break;
|
|
|
|
case 2:
|
|
Ncp = 6240;
|
|
break;
|
|
|
|
case 4:
|
|
Ncp = 448;
|
|
break;
|
|
|
|
default:
|
|
Ncp = 3168;
|
|
break;
|
|
}
|
|
|
|
switch (ue->frame_parms.N_RB_UL) {
|
|
case 6:
|
|
Ncp>>=4;
|
|
prach+=4; // makes prach2 aligned to 128-bit
|
|
break;
|
|
|
|
case 15:
|
|
Ncp>>=3;
|
|
break;
|
|
|
|
case 25:
|
|
Ncp>>=2;
|
|
break;
|
|
|
|
case 50:
|
|
Ncp>>=1;
|
|
break;
|
|
|
|
case 75:
|
|
Ncp=(Ncp*3)>>2;
|
|
break;
|
|
}
|
|
|
|
if (ue->frame_parms.threequarter_fs == 1)
|
|
Ncp=(Ncp*3)>>2;
|
|
|
|
prach2 = prach+(Ncp<<1);
|
|
|
|
// do IDFT
|
|
switch (ue->frame_parms.N_RB_UL) {
|
|
case 6:
|
|
if (prach_fmt == 4) {
|
|
idft(IDFT_256,prachF,prach2,1);
|
|
memmove( prach, prach+512, Ncp<<2 );
|
|
prach_len = 256+Ncp;
|
|
} else {
|
|
idft(IDFT_1536,prachF,prach2,1);
|
|
memmove( prach, prach+3072, Ncp<<2 );
|
|
prach_len = 1536+Ncp;
|
|
|
|
if (prach_fmt>1) {
|
|
memmove( prach2+3072, prach2, 6144 );
|
|
prach_len = 2*1536+Ncp;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 15:
|
|
if (prach_fmt == 4) {
|
|
idft(IDFT_512,prachF,prach2,1);
|
|
//TODO: account for repeated format in dft output
|
|
memmove( prach, prach+1024, Ncp<<2 );
|
|
prach_len = 512+Ncp;
|
|
} else {
|
|
idft(IDFT_3072,prachF,prach2,1);
|
|
memmove( prach, prach+6144, Ncp<<2 );
|
|
prach_len = 3072+Ncp;
|
|
|
|
if (prach_fmt>1) {
|
|
memmove( prach2+6144, prach2, 12288 );
|
|
prach_len = 2*3072+Ncp;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 25:
|
|
default:
|
|
if (prach_fmt == 4) {
|
|
idft(IDFT_1024,prachF,prach2,1);
|
|
memmove( prach, prach+2048, Ncp<<2 );
|
|
prach_len = 1024+Ncp;
|
|
} else {
|
|
idft(IDFT_6144,prachF,prach2,1);
|
|
/*for (i=0;i<6144*2;i++)
|
|
prach2[i]<<=1;*/
|
|
memmove( prach, prach+12288, Ncp<<2 );
|
|
prach_len = 6144+Ncp;
|
|
|
|
if (prach_fmt>1) {
|
|
memmove( prach2+12288, prach2, 24576 );
|
|
prach_len = 2*6144+Ncp;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 50:
|
|
if (prach_fmt == 4) {
|
|
idft(IDFT_2048,prachF,prach2,1);
|
|
memmove( prach, prach+4096, Ncp<<2 );
|
|
prach_len = 2048+Ncp;
|
|
} else {
|
|
idft(IDFT_12288,prachF,prach2,1);
|
|
memmove( prach, prach+24576, Ncp<<2 );
|
|
prach_len = 12288+Ncp;
|
|
|
|
if (prach_fmt>1) {
|
|
memmove( prach2+24576, prach2, 49152 );
|
|
prach_len = 2*12288+Ncp;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 75:
|
|
if (prach_fmt == 4) {
|
|
idft(IDFT_3072,prachF,prach2,1);
|
|
//TODO: account for repeated format in dft output
|
|
memmove( prach, prach+6144, Ncp<<2 );
|
|
prach_len = 3072+Ncp;
|
|
} else {
|
|
idft(IDFT_18432,prachF,prach2,1);
|
|
memmove( prach, prach+36864, Ncp<<2 );
|
|
prach_len = 18432+Ncp;
|
|
|
|
if (prach_fmt>1) {
|
|
memmove( prach2+36834, prach2, 73728 );
|
|
prach_len = 2*18432+Ncp;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 100:
|
|
if (ue->frame_parms.threequarter_fs == 0) {
|
|
if (prach_fmt == 4) {
|
|
idft(IDFT_4096,prachF,prach2,1);
|
|
memmove( prach, prach+8192, Ncp<<2 );
|
|
prach_len = 4096+Ncp;
|
|
} else {
|
|
idft(IDFT_24576,prachF,prach2,1);
|
|
memmove( prach, prach+49152, Ncp<<2 );
|
|
prach_len = 24576+Ncp;
|
|
|
|
if (prach_fmt>1) {
|
|
memmove( prach2+49152, prach2, 98304 );
|
|
prach_len = 2* 24576+Ncp;
|
|
}
|
|
}
|
|
} else {
|
|
if (prach_fmt == 4) {
|
|
idft(IDFT_3072,prachF,prach2,1);
|
|
//TODO: account for repeated format in dft output
|
|
memmove( prach, prach+6144, Ncp<<2 );
|
|
prach_len = 3072+Ncp;
|
|
} else {
|
|
idft(IDFT_18432,prachF,prach2,1);
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//LOG_I(PHY,"prach_len=%d\n",prach_len);
|
|
AssertFatal(prach_fmt<4,
|
|
"prach_fmt4 not fully implemented" );
|
|
|
|
int j;
|
|
int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*ue->frame_parms.samples_per_tti;
|
|
LOG_I( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow );
|
|
|
|
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];
|
|
((int16_t *)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1];
|
|
}
|
|
|
|
for (i=0; i<overflow; i++,j++) {
|
|
((int16_t *)ue->common_vars.txdata[0])[2*i] = prach[2*j];
|
|
((int16_t *)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1];
|
|
}
|
|
|
|
|
|
#if defined(PRACH_WRITE_OUTPUT_DEBUG)
|
|
LOG_M("prach_txF0.m","prachtxF0",prachF,prach_len-Ncp,1,1);
|
|
LOG_M("prach_tx0.m","prachtx0",prach+(Ncp<<1),prach_len-Ncp,1,1);
|
|
LOG_M("txsig.m","txs",(int16_t *)(&ue->common_vars.txdata[0][0]),2*ue->frame_parms.samples_per_tti,1,1);
|
|
exit(-1);
|
|
#endif
|
|
return signal_energy( (int *)prach, 256 );
|
|
}
|
|
|