685 lines
24 KiB
C
685 lines
24 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.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
|
|
*/
|
|
#include "PHY/sse_intrin.h"
|
|
#include "PHY/defs_eNB.h"
|
|
//#include "PHY/phy_extern.h"
|
|
//#include "prach.h"
|
|
#include "PHY/LTE_TRANSPORT/if4_tools.h"
|
|
|
|
#include "SCHED/sched_eNB.h"
|
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
|
#include "prach_extern.h"
|
|
#include <openair1/PHY/LTE_TRANSPORT/transport_proto.h>
|
|
#include "common/utils/lte/prach_utils.h"
|
|
|
|
void rx_prach0(PHY_VARS_eNB *eNB,
|
|
RU_t *ru,
|
|
int frame_prach,
|
|
int subframe,
|
|
uint16_t *max_preamble,
|
|
uint16_t *max_preamble_energy,
|
|
uint16_t *max_preamble_delay,
|
|
int16_t *avg_preamble_energy,
|
|
uint16_t Nf,
|
|
uint8_t tdd_mapindex,
|
|
uint8_t br_flag,
|
|
uint8_t ce_level
|
|
) {
|
|
int i;
|
|
frame_type_t frame_type;
|
|
uint16_t rootSequenceIndex;
|
|
uint8_t prach_ConfigIndex;
|
|
uint8_t Ncs_config;
|
|
uint8_t restricted_set;
|
|
uint8_t n_ra_prb;
|
|
int16_t **rxsigF=NULL;
|
|
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;
|
|
uint16_t d_start=0;
|
|
uint16_t numshift = 0;
|
|
uint8_t not_found;
|
|
int k=0;
|
|
uint16_t u;
|
|
c16_t *Xu=0;
|
|
int16_t Ncp;
|
|
uint16_t first_nonzero_root_idx=0;
|
|
uint8_t new_dft=0;
|
|
int32_t lev;
|
|
int16_t levdB;
|
|
int fft_size=0,log2_ifft_size;
|
|
int16_t prach_ifft_tmp[2048*2] __attribute__((aligned(32)));
|
|
int32_t *prach_ifft=(int32_t *)NULL;
|
|
int32_t **prach_ifftp=(int32_t **)NULL;
|
|
int prach_ifft_cnt=0;
|
|
int exit_flag=0;
|
|
LTE_DL_FRAME_PARMS *fp;
|
|
int nb_rx;
|
|
if(eNB) {
|
|
fp = &(eNB->frame_parms);
|
|
nb_rx = fp->nb_antennas_rx;
|
|
} else {
|
|
fp = (ru->frame_parms);
|
|
nb_rx = ru->nb_rx;
|
|
}
|
|
|
|
AssertFatal(fp!=NULL,"rx_prach called without valid RU or eNB descriptor\n");
|
|
frame_type = fp->frame_type;
|
|
|
|
if (br_flag == 1) {
|
|
AssertFatal(fp->prach_emtc_config_common.prach_Config_enabled==1,
|
|
"emtc prach_Config is not enabled\n");
|
|
AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1,
|
|
"ce_level %d is not active\n",ce_level);
|
|
rootSequenceIndex = fp->prach_emtc_config_common.rootSequenceIndex;
|
|
prach_ConfigIndex = fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[ce_level];
|
|
Ncs_config = fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
|
|
restricted_set = fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag;
|
|
n_ra_prb = get_prach_prb_offset(fp->frame_type,fp->tdd_config,fp->N_RB_UL,fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[ce_level],
|
|
fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level],
|
|
tdd_mapindex,Nf);
|
|
// update pointers to results for ce_level
|
|
max_preamble += ce_level;
|
|
max_preamble_energy += ce_level;
|
|
max_preamble_delay += ce_level;
|
|
} else {
|
|
rootSequenceIndex = fp->prach_config_common.rootSequenceIndex;
|
|
prach_ConfigIndex = fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
|
|
Ncs_config = fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
|
|
restricted_set = fp->prach_config_common.prach_ConfigInfo.highSpeedFlag;
|
|
n_ra_prb = get_prach_prb_offset(fp->frame_type,fp->tdd_config,fp->N_RB_UL,fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex,
|
|
fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,
|
|
tdd_mapindex,Nf);
|
|
}
|
|
|
|
uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
|
|
uint16_t N_ZC = (prach_fmt <4)?839:139;
|
|
if (eNB) {
|
|
if (br_flag == 1) {
|
|
prach_ifftp = eNB->prach_vars_br.prach_ifft[ce_level];
|
|
rxsigF = eNB->prach_vars_br.rxsigF[ce_level];
|
|
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
if (((frame_prach)&1023) < 20) LOG_D(PHY,
|
|
"PRACH (eNB) : running rx_prach (br_flag %d, ce_level %d) for frame %d subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d, rootSequenceIndex %d, repetition number %d,numRepetitionsPrePreambleAttempt %d\n",
|
|
br_flag,ce_level,frame_prach,subframe,
|
|
fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level],
|
|
prach_ConfigIndex,rootSequenceIndex,
|
|
eNB->prach_vars_br.repetition_number[ce_level],
|
|
fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level]);
|
|
}
|
|
} else {
|
|
prach_ifftp = eNB->prach_vars.prach_ifft[0];
|
|
rxsigF = eNB->prach_vars.rxsigF[0];
|
|
|
|
if (((frame_prach) & 1023) < 20)
|
|
LOG_D(PHY,
|
|
"PRACH (eNB) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d , rootSequenceIndex %d\n",
|
|
subframe,
|
|
fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,
|
|
prach_ConfigIndex,
|
|
rootSequenceIndex);
|
|
}
|
|
} else {
|
|
if (br_flag == 1) {
|
|
rxsigF = ru->prach_rxsigF_br[ce_level];
|
|
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
if (((frame_prach)&1023) < 20) LOG_D(PHY,"PRACH (RU) : running rx_prach (br_flag %d, ce_level %d) for frame %d subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n",
|
|
br_flag,ce_level,frame_prach,subframe,fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level],prach_ConfigIndex);
|
|
}
|
|
} else {
|
|
rxsigF = ru->prach_rxsigF[0];
|
|
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
if (((frame_prach)&1023) < 20) LOG_D(PHY,"PRACH (RU) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n",
|
|
subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
AssertFatal(ru!=NULL,"ru is null\n");
|
|
int8_t dBEn0=0;
|
|
int16_t *prach[nb_rx];
|
|
memset(prach, 0, nb_rx * sizeof(int16_t*));
|
|
|
|
for (int aa=0; aa<nb_rx; aa++) {
|
|
if (ru->if_south == LOCAL_RF || ru->function == NGFI_RAU_IF5) { // set the time-domain signal if we have to use it in this node
|
|
// DJP - indexing below in subframe zero takes us off the beginning of the array???
|
|
prach[aa] = (int16_t *)&ru->common.rxdata[aa][(subframe*fp->samples_per_tti)-ru->N_TA_offset];
|
|
|
|
if (LOG_DUMPFLAG(DEBUG_PRACH)) {
|
|
int32_t en0=signal_energy((int32_t *)prach[aa],fp->samples_per_tti);
|
|
dBEn0 = dB_fixed(en0);
|
|
int8_t rach_dBm = dBEn0 - ru->rx_total_gain_dB;
|
|
char buffer[80];
|
|
|
|
if (dBEn0>30 && prach[0]!= NULL) {
|
|
static int counter=0;
|
|
sprintf(buffer, "%s%d", "/tmp/prach_rx.m",counter);
|
|
LOG_M(buffer,"prach_rx",prach[0],fp->samples_per_tti,1,1);
|
|
exit_flag=1;
|
|
}
|
|
|
|
if (dBEn0>30) {
|
|
sprintf(buffer, "rach_dBm:%d",rach_dBm);
|
|
|
|
if (prach[0]!= NULL) LOG_M("prach_rx.m","prach_rx",prach[0],fp->samples_per_tti,1,1);
|
|
|
|
LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d per_tti:%d prach:%p (energy %d) TA:%d %s rxdata:%p index:%d\n",
|
|
ru->idx,br_flag,ce_level,frame_prach,subframe,fp->samples_per_tti,
|
|
prach[aa],dBEn0,ru->N_TA_offset,buffer,ru->common.rxdata[aa],
|
|
(subframe*fp->samples_per_tti)-ru->N_TA_offset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// First compute physical root sequence
|
|
if (restricted_set == 0) {
|
|
AssertFatal(Ncs_config<=15,
|
|
"Illegal Ncs_config for unrestricted format %d\n",Ncs_config);
|
|
NCS = NCS_unrestricted[Ncs_config];
|
|
} else {
|
|
AssertFatal(Ncs_config<=14,
|
|
"FATAL, Illegal Ncs_config for restricted format %d\n",Ncs_config);
|
|
NCS = NCS_restricted[Ncs_config];
|
|
}
|
|
|
|
if (eNB) start_meas(&eNB->rx_prach);
|
|
|
|
const uint16_t *prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
|
|
// 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);
|
|
|
|
if (NCS2==0)
|
|
NCS2 = N_ZC;
|
|
|
|
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;
|
|
}
|
|
|
|
// Adjust CP length based on UL bandwidth
|
|
switch (fp->N_RB_UL) {
|
|
case 6:
|
|
Ncp>>=4;
|
|
break;
|
|
|
|
case 15:
|
|
Ncp>>=3;
|
|
break;
|
|
|
|
case 25:
|
|
Ncp>>=2;
|
|
break;
|
|
|
|
case 50:
|
|
Ncp>>=1;
|
|
break;
|
|
|
|
case 75:
|
|
Ncp=(Ncp*3)>>2;
|
|
break;
|
|
|
|
case 100:
|
|
if (fp->threequarter_fs == 1)
|
|
Ncp=(Ncp*3)>>2;
|
|
|
|
break;
|
|
}
|
|
|
|
if (((eNB!=NULL) && (ru->function != NGFI_RAU_IF4p5))||
|
|
((eNB==NULL) && (ru->function == NGFI_RRU_IF4p5))) { // compute the DFTs of the PRACH temporal resources
|
|
// Do forward transform
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
LOG_D(PHY,"rx_prach: Doing FFT for N_RB_UL %d nb_rx:%d Ncp:%d\n",fp->N_RB_UL, nb_rx, Ncp);
|
|
}
|
|
|
|
for (int aa=0; aa<nb_rx; aa++) {
|
|
AssertFatal(prach[aa]!=NULL,"prach[%d] is null\n",aa);
|
|
int16_t *prach2 = prach[aa] + (Ncp<<1); // <<1 because type int16 but input is c16
|
|
|
|
// do DFT
|
|
switch (fp->N_RB_UL) {
|
|
case 6:
|
|
fft_size = prach_fmt == 4 ? 256 : 1536;
|
|
break;
|
|
|
|
case 15:
|
|
fft_size = prach_fmt == 4 ? 256 : 3072;
|
|
break;
|
|
|
|
case 25:
|
|
default:
|
|
fft_size = prach_fmt == 4 ? 1024 : 6144;
|
|
break;
|
|
|
|
case 50:
|
|
fft_size = prach_fmt == 4 ? 2048 : 12288;
|
|
break;
|
|
|
|
case 75:
|
|
fft_size = prach_fmt == 4 ? 3072 : 18432;
|
|
break;
|
|
|
|
case 100:
|
|
if (fp->threequarter_fs == 0)
|
|
fft_size = prach_fmt == 4 ? 4096 : 24576;
|
|
else
|
|
fft_size = prach_fmt == 4 ? 3072 : 18432;
|
|
break;
|
|
}
|
|
|
|
dft(get_dft(fft_size), prach2, rxsigF[aa], 1);
|
|
if (prach_fmt > 1 && prach_fmt != 4)
|
|
dft(get_dft(fft_size), prach2 + 2 * fft_size, rxsigF[aa] + 2 * fft_size, 1);
|
|
|
|
k = (12*n_ra_prb) - 6*fp->N_RB_UL;
|
|
|
|
if (k<0) {
|
|
k+=(fp->ofdm_symbol_size);
|
|
}
|
|
|
|
k*=12;
|
|
k+=13;
|
|
k*=2;
|
|
int dftsize_x2 = fp->ofdm_symbol_size*24;
|
|
//LOG_D(PHY,"Shifting prach_rxF from %d to 0\n",k);
|
|
|
|
if ((k+(839*2)) > dftsize_x2) { // PRACH signal is split around DC
|
|
memmove((void *)&rxsigF[aa][dftsize_x2-k],(void *)&rxsigF[aa][0],(k+(839*2)-dftsize_x2)*2);
|
|
memmove((void *)&rxsigF[aa][0],(void *)(&rxsigF[aa][k]),(dftsize_x2-k)*2);
|
|
} else // PRACH signal is not split around DC
|
|
memmove((void *)&rxsigF[aa][0],(void *)(&rxsigF[aa][k]),839*4);
|
|
}
|
|
}
|
|
|
|
if (!eNB) {
|
|
if (ru->function == NGFI_RRU_IF4p5) {
|
|
/// **** send_IF4 of rxsigF to RAU **** ///
|
|
if (br_flag == 1)
|
|
send_IF4p5(ru, frame_prach, subframe, IF4p5_PRACH + 1 + ce_level);
|
|
else
|
|
send_IF4p5(ru, frame_prach, subframe, IF4p5_PRACH);
|
|
} else {
|
|
LOG_E(PHY, "inconsistent case\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0], 840));
|
|
if ((en > 10) && (br_flag == 1))
|
|
LOG_I(PHY,
|
|
"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",
|
|
br_flag,
|
|
ce_level,
|
|
n_ra_prb,
|
|
k,
|
|
frame_prach,
|
|
subframe,
|
|
en);
|
|
}
|
|
|
|
// in case of RAU and prach received rx_thread wakes up prach
|
|
// here onwards is for eNodeB_3GPP or NGFI_RAU_IF4p5
|
|
preamble_offset_old = 99;
|
|
uint8_t update_TA = 4;
|
|
uint8_t update_TA2 = 1;
|
|
|
|
switch (eNB->frame_parms.N_RB_DL) {
|
|
case 6:
|
|
update_TA = 16;
|
|
break;
|
|
|
|
case 25:
|
|
update_TA = 4;
|
|
break;
|
|
|
|
case 50:
|
|
update_TA = 2;
|
|
break;
|
|
|
|
case 75:
|
|
update_TA = 3;
|
|
update_TA2 = 2;
|
|
break;
|
|
|
|
case 100:
|
|
update_TA = 1;
|
|
break;
|
|
}
|
|
|
|
*max_preamble_energy=0;
|
|
*avg_preamble_energy=0;
|
|
uint64_t avg_en=0;
|
|
|
|
for (preamble_index=0 ; preamble_index<64 ; preamble_index++) {
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
// int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
|
|
|
|
if (dBEn0>30) LOG_I(PHY,"frame %d, subframe %d : Trying preamble %d (br_flag %d)\n",frame_prach,subframe,preamble_index,br_flag);
|
|
}
|
|
|
|
if (restricted_set == 0) {
|
|
// 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)));
|
|
|
|
if (preamble_offset != preamble_offset_old) {
|
|
preamble_offset_old = preamble_offset;
|
|
new_dft = 1;
|
|
// This is the \nu corresponding to the preamble index
|
|
preamble_shift = 0;
|
|
} else {
|
|
preamble_shift -= NCS;
|
|
|
|
if (preamble_shift < 0)
|
|
preamble_shift+=N_ZC;
|
|
}
|
|
} else { // This is the high-speed case
|
|
new_dft = 0;
|
|
|
|
// 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) {
|
|
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
|
|
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;
|
|
// skip to next root and recompute parameters if numshift==0
|
|
(numshift>0) ? (not_found = 0) : (preamble_offset++);
|
|
}
|
|
}
|
|
|
|
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)
|
|
else
|
|
preamble_shift = 0;
|
|
|
|
if (preamble_shift < 0)
|
|
preamble_shift+=N_ZC;
|
|
|
|
preamble_index0++;
|
|
|
|
if (preamble_index == 0)
|
|
first_nonzero_root_idx = preamble_offset;
|
|
}
|
|
|
|
// Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
//en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
|
|
|
|
if (dBEn0>30) LOG_I(PHY,"frame %d, subframe %d : preamble index %d: offset %d, preamble shift %d (br_flag %d, en %d)\n",
|
|
frame_prach,subframe,preamble_index,preamble_offset,preamble_shift,br_flag,dBEn0);
|
|
}
|
|
|
|
log2_ifft_size = 10;
|
|
|
|
if (new_dft == 1) {
|
|
new_dft = 0;
|
|
|
|
if (br_flag == 1) {
|
|
Xu = eNB->X_u_br[ce_level][preamble_offset - first_nonzero_root_idx];
|
|
prach_ifft = prach_ifftp[prach_ifft_cnt++];
|
|
|
|
if (eNB->prach_vars_br.repetition_number[ce_level]==1) memset(prach_ifft,0,((N_ZC==839)?2048:256)*sizeof(int32_t));
|
|
} else {
|
|
Xu=(c16_t *)eNB->X_u[preamble_offset-first_nonzero_root_idx];
|
|
prach_ifft = prach_ifftp[0];
|
|
memset(prach_ifft,0,((N_ZC==839) ? 2048 : 256)*sizeof(int32_t));
|
|
}
|
|
c16_t prachF[1024] __attribute__((aligned(32)))={0};
|
|
|
|
if (LOG_DUMPFLAG(DEBUG_PRACH))
|
|
for (int z=0; z<nb_rx; z++)
|
|
if( prach[z] ) {
|
|
char tmp[128];
|
|
sprintf(tmp,"prach_rx%d.m", z);
|
|
LOG_M(tmp,tmp,prach[z],6144+792,1,1);
|
|
sprintf(tmp,"prach_rxF%d.m", z);
|
|
LOG_M(tmp,tmp,rxsigF[z],12288,1,1);
|
|
}
|
|
|
|
for (int aa=0; aa<nb_rx; aa++) {
|
|
// Do componentwise product with Xu* on each antenna
|
|
k=0;
|
|
|
|
for (int offset=0; offset<N_ZC; offset++) {
|
|
prachF[offset].r = (int16_t)(((int32_t)Xu[offset].r*rxsigF[aa][k] + (int32_t)Xu[offset].i*rxsigF[aa][k+1])>>15);
|
|
prachF[offset].i = (int16_t)(((int32_t)Xu[offset].r*rxsigF[aa][k+1] - (int32_t)Xu[offset].i*rxsigF[aa][k])>>15);
|
|
k+=2;
|
|
|
|
if (k==(12*2*fp->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;
|
|
idft(IDFT_1024,(int16_t*)prachF,prach_ifft_tmp,1);
|
|
|
|
// compute energy and accumulate over receive antennas and repetitions for BR
|
|
for (i=0; i<2048; i++)
|
|
prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[i<<1] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>9;
|
|
} else {
|
|
idft(IDFT_256,(int16_t*)prachF,prach_ifft_tmp,1);
|
|
log2_ifft_size = 8;
|
|
|
|
// compute energy and accumulate over receive antennas and repetitions for BR
|
|
for (i=0; i<256; i++)
|
|
prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[(i<<1)] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>9;
|
|
}
|
|
|
|
if (LOG_DUMPFLAG(DEBUG_PRACH)) {
|
|
if (aa==0) LOG_M("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
|
|
|
|
if (aa==1) LOG_M("prach_rxF_comp1.m","prach_rxF_comp1",prachF,1024,1,1);
|
|
}
|
|
}// antennas_rx
|
|
} // new dft
|
|
|
|
// check energy in nth time shift, for
|
|
if ((br_flag==0) ||
|
|
(eNB->prach_vars_br.repetition_number[ce_level]==
|
|
eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) {
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
|
|
|
|
if (en>60) LOG_I(PHY,"frame %d, subframe %d: Checking for peak in time-domain (br_flag %d, en %d)\n",frame_prach,subframe,br_flag,en);
|
|
}
|
|
|
|
preamble_shift2 = ((preamble_shift==0) ? 0 : ((preamble_shift<<log2_ifft_size)/N_ZC));
|
|
|
|
for (i=0; i<NCS2; i++) {
|
|
lev = (int32_t)prach_ifft[(preamble_shift2+i)];
|
|
avg_en += lev;
|
|
levdB = dB_fixed_x10(lev);
|
|
|
|
if (levdB>*max_preamble_energy) {
|
|
*max_preamble_energy = levdB;
|
|
*max_preamble_delay = ((i*fft_size)>>log2_ifft_size)*update_TA/update_TA2;
|
|
*max_preamble = preamble_index;
|
|
|
|
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
|
// int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
|
|
|
|
if (dBEn0>30)
|
|
LOG_D(PHY,"frame %d, subframe %d : max_preamble_energy %d, max_preamble_delay %d, max_preamble %d (br_flag %d,ce_level %d, levdB %d, lev %d)\n",
|
|
frame_prach,subframe,
|
|
*max_preamble_energy,*max_preamble_delay,
|
|
*max_preamble,br_flag,ce_level,levdB,lev);
|
|
}
|
|
}
|
|
} ///ncs2
|
|
}
|
|
}// preamble_index
|
|
|
|
*avg_preamble_energy=dB_fixed(avg_en/64);
|
|
|
|
if (exit_flag==1) {
|
|
int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
|
|
|
|
if (en>30) {
|
|
k = (12*n_ra_prb) - 6*fp->N_RB_UL;
|
|
|
|
if (k<0) k+=fp->ofdm_symbol_size;
|
|
|
|
k*=12;
|
|
k+=13;
|
|
k*=2;
|
|
|
|
if (br_flag == 0) {
|
|
LOG_M("rxsigF.m","prach_rxF",&rxsigF[0][0],12288,1,1);
|
|
LOG_M("Xu.m","xu",Xu,N_ZC,1,1);
|
|
LOG_M("prach_ifft0.m","prach_t0",prach_ifft,1024,1,1);
|
|
LOG_M("SF2_3.m","sf2_3",&ru->common.rxdata[0][2*fp->samples_per_tti],2*fp->samples_per_tti,1,1);
|
|
} else {
|
|
LOG_E(PHY,"Dumping prach (br_flag %d), k = %d (n_ra_prb %d)\n",br_flag,k,n_ra_prb);
|
|
LOG_M("rxsigF_br.m","prach_rxF_br",&rxsigF[0][0],12288,1,1);
|
|
LOG_M("Xu_br.m","xu_br",Xu,N_ZC,1,1);
|
|
LOG_M("prach_ifft0_br.m","prach_t0_br",prach_ifft,1024,1,1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (eNB) stop_meas(&eNB->rx_prach);
|
|
AssertFatal(exit_flag==0,"exiting\n");
|
|
|
|
}
|
|
|
|
|
|
void rx_prach(PHY_VARS_eNB *eNB,
|
|
RU_t *ru,
|
|
uint16_t *max_preamble,
|
|
uint16_t *max_preamble_energy,
|
|
uint16_t *max_preamble_delay,
|
|
int16_t *avg_preamble_energy,
|
|
uint16_t Nf,
|
|
uint8_t tdd_mapindex,
|
|
uint8_t br_flag) {
|
|
int i;
|
|
int prach_mask=0;
|
|
|
|
int subframe;
|
|
if (eNB)
|
|
subframe= br_flag?eNB->proc.subframe_prach_br:eNB->proc.subframe_prach;
|
|
else
|
|
subframe= br_flag?ru->proc.subframe_prach_br:ru->proc.subframe_prach;
|
|
|
|
int frame_prach=eNB?eNB->proc.frame_prach: ru->proc.frame_prach;
|
|
|
|
if (br_flag == 0) {
|
|
rx_prach0(eNB,ru,frame_prach,subframe,max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,0,0);
|
|
} else { // This is procedure for eMTC, basically handling the repetitions
|
|
prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br);
|
|
|
|
for (i=0; i<4; i++) {
|
|
if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i]==1) &&
|
|
((prach_mask&(1<<(i+1))) > 0)) { // check that prach CE level is active now
|
|
|
|
// if first reception in group of repetitions store frame for later (in RA-RNTI for Msg2)
|
|
if (eNB->prach_vars_br.repetition_number[i]==0) eNB->prach_vars_br.first_frame[i]=eNB->proc.frame_prach_br;
|
|
|
|
// increment repetition number
|
|
eNB->prach_vars_br.repetition_number[i]++;
|
|
// do basic PRACH reception
|
|
rx_prach0(eNB,ru,frame_prach,subframe,max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,1,i);
|
|
|
|
// if last repetition, clear counter
|
|
if (eNB->prach_vars_br.repetition_number[i] == eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[i]) {
|
|
eNB->prach_vars_br.repetition_number[i]=0;
|
|
}
|
|
}
|
|
} /* for i ... */
|
|
} /* else br_flag == 0 */
|
|
}
|
|
|
|
|
|
|