PSBCH RX TX and SLSS search procedures

- RX/TX Phy processing accg to 38.211, 38.212 Rel16
	- PSBCH simulator used to validate TX/RX phy processing
	- PSBCH SLSS Search procedures
	- PSBCH SIM also tests SLSS SEARCH
This commit is contained in:
Raghavendra Dinavahi
2024-04-12 16:07:00 +02:00
committed by Robert Schmidt
parent 1244c9a278
commit 94b23d1eb0
35 changed files with 3069 additions and 113 deletions
@@ -0,0 +1,57 @@
/*
* 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/CODING/nrPolar_tools/nr_polar_psbch_defs.h
\brief Polar definitions required for Sidelink PSBCH
\author
\date
\version
\company: Fraunhofer
\email:
\note
\warning
*/
#ifndef __NR_POLAR_PSBCH_DEFS__H__
#define __NR_POLAR_PSBCH_DEFS__H__
//PSBCH related polar parameters.
//PSBCH symbols sent in 11RBS, 9 symbols. 11*9*(12-3(for DMRS))*2bits = 1782 bits
#define SL_NR_POLAR_PSBCH_E_NORMAL_CP 1782
//PSBCH symbols sent in 11RBS, 7 symbols. 11*7*(12-3(for DMRS))*2bits = 1386 bits
#define SL_NR_POLAR_PSBCH_E_EXT_CP 1386
// SL_NR_POLAR_PSBCH_E_NORMAL_CP/32
#define SL_NR_POLAR_PSBCH_E_DWORD 56
#define SL_NR_POLAR_PSBCH_MESSAGE_TYPE (NR_POLAR_UCI_PUCCH_MESSAGE_TYPE + 1)
#define SL_NR_POLAR_PSBCH_PAYLOAD_BITS 32
#define SL_NR_POLAR_PSBCH_AGGREGATION_LEVEL 0
#define SL_NR_POLAR_PSBCH_N_MAX 9
#define SL_NR_POLAR_PSBCH_I_IL 1
#define SL_NR_POLAR_PSBCH_I_SEG 0
#define SL_NR_POLAR_PSBCH_N_PC 0
#define SL_NR_POLAR_PSBCH_N_PC_WM 0
#define SL_NR_POLAR_PSBCH_I_BIL 0
#define SL_NR_POLAR_PSBCH_CRC_PARITY_BITS 24
#define SL_NR_POLAR_PSBCH_CRC_ERROR_CORRECTION_BITS 3
#endif
+14 -1
View File
@@ -32,6 +32,7 @@
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
#include "PHY/NR_TRANSPORT/nr_dci.h"
#include "nrPolar_tools/nr_polar_psbch_defs.h"
#define PolarKey ((messageType<<24)|(messageLength<<8)|aggregation_level)
static t_nrPolar_params * PolarList=NULL;
@@ -191,7 +192,19 @@ t_nrPolar_params *nr_polar_params(int8_t messageType, uint16_t messageLength, ui
newPolarInitNode->payloadBits = messageLength;
newPolarInitNode->crcCorrectionBits = NR_POLAR_PUCCH_CRC_ERROR_CORRECTION_BITS;
//LOG_D(PHY,"New polar node, encoderLength %d, aggregation_level %d\n",newPolarInitNode->encoderLength,aggregation_level);
} else if (messageType == SL_NR_POLAR_PSBCH_MESSAGE_TYPE) { //PSBCH
newPolarInitNode->n_max = SL_NR_POLAR_PSBCH_N_MAX;
newPolarInitNode->i_il = SL_NR_POLAR_PSBCH_I_IL;
newPolarInitNode->i_seg = SL_NR_POLAR_PSBCH_I_SEG;
newPolarInitNode->n_pc = SL_NR_POLAR_PSBCH_N_PC;
newPolarInitNode->n_pc_wm = SL_NR_POLAR_PSBCH_N_PC_WM;
newPolarInitNode->i_bil = SL_NR_POLAR_PSBCH_I_BIL;
newPolarInitNode->crcParityBits = SL_NR_POLAR_PSBCH_CRC_PARITY_BITS;
newPolarInitNode->payloadBits = SL_NR_POLAR_PSBCH_PAYLOAD_BITS;
newPolarInitNode->encoderLength = SL_NR_POLAR_PSBCH_E_NORMAL_CP + 2;
newPolarInitNode->crcCorrectionBits = SL_NR_POLAR_PSBCH_CRC_ERROR_CORRECTION_BITS;
newPolarInitNode->crc_generator_matrix = crc24c_generator_matrix(newPolarInitNode->payloadBits);//G_P
LOG_D(PHY,"SIDELINK: Initializing polar parameters for PSBCH (K %d, E %d)\n",newPolarInitNode->payloadBits,newPolarInitNode->encoderLength);
} else {
AssertFatal(1 == 0, "[nr_polar_init] Incorrect Message Type(%d)", messageType);
}
+45 -1
View File
@@ -32,7 +32,6 @@
#include "PHY/NR_REFSIG/ul_ref_seq_nr.h"
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
#include "PHY/NR_REFSIG/nr_refsig.h"
#include "PHY/MODULATION/nr_modulation.h"
#include "openair2/COMMON/prs_nr_paramdef.h"
#include "SCHED_NR_UE/harq_nr.h"
@@ -384,6 +383,16 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
return 0;
}
static void sl_ue_free(PHY_VARS_NR_UE *UE)
{
if (UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation) {
free_and_zero(UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[0]);
free_and_zero(UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[1]);
free_and_zero(UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation);
}
}
void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
{
const NR_DL_FRAME_PARMS* fp = &ue->frame_parms;
@@ -489,6 +498,8 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
free_and_zero(ue->prs_vars[idx]);
}
sl_ue_free(ue);
}
void free_nr_ue_dl_harq(NR_DL_UE_HARQ_t harq_list[2][NR_MAX_DLSCH_HARQ_PROCESSES], int number_of_processes, int num_rb) {
@@ -702,3 +713,36 @@ void phy_term_nr_top(void)
free_ul_reference_signal_sequences();
free_context_synchro_nr();
}
void sl_ue_phy_init(PHY_VARS_NR_UE *UE)
{
uint16_t scaling_value = ONE_OVER_SQRT2_Q15;
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
if (!UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation) {
UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation = (int32_t **)malloc16_clear(SL_NR_NUM_IDs_IN_PSS *sizeof(int32_t *) );
UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[0] = (int32_t *)malloc16_clear( sizeof(int32_t)*sl_fp->ofdm_symbol_size);
UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[1] = (int32_t *)malloc16_clear( sizeof(int32_t)*sl_fp->ofdm_symbol_size);
}
LOG_I(PHY, "SIDELINK INIT: GENERATE PSS, SSS, GOLD SEQUENCES AND PSBCH DMRS SEQUENCES FOR ALL possible SLSS IDs 0- 671\n");
// Generate PSS sequences for IDs 0,1 used in PSS
sl_generate_pss(&UE->SL_UE_PHY_PARAMS.init_params,0, scaling_value);
sl_generate_pss(&UE->SL_UE_PHY_PARAMS.init_params,1, scaling_value);
// Generate psbch dmrs Gold Sequences and modulated dmrs symbols
sl_init_psbch_dmrs_gold_sequences(UE);
for (int slss_id = 0; slss_id < SL_NR_NUM_SLSS_IDs; slss_id++) {
sl_generate_psbch_dmrs_qpsk_sequences(UE, UE->SL_UE_PHY_PARAMS.init_params.psbch_dmrs_modsym[slss_id], slss_id);
sl_generate_sss(&UE->SL_UE_PHY_PARAMS.init_params, slss_id, scaling_value);
}
// Generate PSS time domain samples used for correlation during SLSS reception.
sl_generate_pss_ifft_samples(&UE->SL_UE_PHY_PARAMS, &UE->SL_UE_PHY_PARAMS.init_params);
init_symbol_rotation(sl_fp);
init_timeshift_rotation(sl_fp);
}
+3 -2
View File
@@ -425,7 +425,8 @@ void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp)
LOG_I(PHY,"fp->samples_per_frame=%d\n",fp->samples_per_frame);
LOG_I(PHY,"fp->dl_CarrierFreq=%lu\n",fp->dl_CarrierFreq);
LOG_I(PHY,"fp->ul_CarrierFreq=%lu\n",fp->ul_CarrierFreq);
LOG_I(PHY,"fp->Nid_cell=%d\n",fp->Nid_cell);
LOG_I(PHY,"fp->first_carrier_offset=%d\n",fp->first_carrier_offset);
LOG_I(PHY,"fp->ssb_start_subcarrier=%d\n",fp->ssb_start_subcarrier);
}
+1
View File
@@ -61,4 +61,5 @@ void init_delay_table(uint16_t ofdm_symbol_size,
int max_ofdm_symbol_size,
c16_t delay_table[][max_ofdm_symbol_size]);
void sl_ue_phy_init(PHY_VARS_NR_UE *UE);
#endif
+9 -1
View File
@@ -49,9 +49,17 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue,
int reset_freq_est);
int nr_slot_fep(PHY_VARS_NR_UE *ue,
NR_DL_FRAME_PARMS *frame_parms,
const UE_nr_rxtx_proc_t *proc,
unsigned char symbol,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
uint32_t linktype);
int sl_nr_slot_fep(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
unsigned char symbol,
unsigned char Ns,
uint32_t sample_offset,
c16_t rxdataF[][ue->SL_UE_PHY_PARAMS.sl_frame_params.samples_per_slot_wCP]);
int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
+97 -3
View File
@@ -34,12 +34,106 @@
#define LOG_I(A,B...) printf(A)
#endif*/
int sl_nr_slot_fep(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
unsigned char symbol,
unsigned char Ns,
uint32_t sample_offset,
c16_t rxdataF[][ue->SL_UE_PHY_PARAMS.sl_frame_params.samples_per_slot_wCP])
{
NR_DL_FRAME_PARMS *frame_params = &ue->SL_UE_PHY_PARAMS.sl_frame_params;
NR_UE_COMMON *common_vars = &ue->common_vars;
AssertFatal(symbol < frame_params->symbols_per_slot, "slot_fep: symbol must be between 0 and %d\n", frame_params->symbols_per_slot-1);
AssertFatal(Ns < frame_params->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_params->slots_per_frame-1);
unsigned int nb_prefix_samples = frame_params->nb_prefix_samples;
unsigned int nb_prefix_samples0 = frame_params->nb_prefix_samples0;
dft_size_idx_t dftsize = get_dft(frame_params->ofdm_symbol_size);
// This is for misalignment issues
int32_t tmp_dft_in[8192] __attribute__ ((aligned (32)));
unsigned int rx_offset = frame_params->get_samples_slot_timestamp(Ns,frame_params,0);
unsigned int abs_symbol = Ns * frame_params->symbols_per_slot + symbol;
rx_offset += sample_offset;
for (int idx_symb = Ns*frame_params->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++)
rx_offset += (idx_symb%(0x7<<frame_params->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0;
rx_offset += frame_params->ofdm_symbol_size * symbol;
// use OFDM symbol from within 1/8th of the CP to avoid ISI
rx_offset -= (nb_prefix_samples / frame_params->ofdm_offset_divisor);
#ifdef SL_DEBUG_SLOT_FEP
// if (ue->frame <100)
LOG_I(PHY, "slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u\n",
Ns, symbol, nb_prefix_samples, nb_prefix_samples0, rx_offset);
#endif
for (unsigned char aa=0; aa<frame_params->nb_antennas_rx; aa++) {
memset(&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],0,frame_params->ofdm_symbol_size*sizeof(int32_t));
int16_t *rxdata_ptr = (int16_t *)&common_vars->rxdata[aa][rx_offset];
// if input to dft is not 256-bit aligned
if ((rx_offset & 7) != 0) {
memcpy((void *)&tmp_dft_in[0],
(void *)&common_vars->rxdata[aa][rx_offset],
frame_params->ofdm_symbol_size * sizeof(int32_t));
rxdata_ptr = (int16_t *)tmp_dft_in;
}
dft(dftsize,
rxdata_ptr,
(int16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
1);
int symb_offset = (Ns%frame_params->slots_per_subframe)*frame_params->symbols_per_slot;
int32_t rot2 = ((uint32_t*)frame_params->symbol_rotation[1])[symbol+symb_offset];
((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
#ifdef SL_DEBUG_SLOT_FEP
// if (ue->frame <100)
LOG_I(PHY, "slot_fep: slot %d, symbol %d rx_offset %u, rotation symbol %d %d.%d\n", Ns,symbol, rx_offset,
symbol+symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]);
#endif
rotate_cpx_vector((c16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
(c16_t *)&rot2,
(c16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
frame_params->ofdm_symbol_size,
15);
int16_t *shift_rot = (int16_t *)frame_params->timeshift_symbol_rotation;
multadd_cpx_vector((int16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
shift_rot,
(int16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
1,
frame_params->ofdm_symbol_size,
15);
}
LOG_D(PHY, "SIDELINK RX: Slot FEP: done for symbol:%d\n", symbol);
return 0;
}
int nr_slot_fep(PHY_VARS_NR_UE *ue,
NR_DL_FRAME_PARMS *frame_parms,
const UE_nr_rxtx_proc_t *proc,
unsigned char symbol,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
uint32_t linktype)
{
NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
NR_UE_COMMON *common_vars = &ue->common_vars;
int Ns = proc->nr_slot_rx;
@@ -98,7 +192,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
apply_nr_rotation_RX(frame_parms,
rxdataF[aa],
frame_parms->symbol_rotation[0],
frame_parms->symbol_rotation[linktype],
Ns,
frame_parms->N_RB_DL,
0,
+23 -13
View File
@@ -202,22 +202,32 @@ int nr_pdcch_dmrs_rx(PHY_VARS_NR_UE *ue,
return(0);
}
void nr_pbch_dmrs_rx(const int symbol, const unsigned int *nr_gold_pbch, c16_t *output)
void nr_pbch_dmrs_rx(int symbol,
unsigned int *nr_gold_pbch,
c16_t *output,
bool sidelink)
{
int m,m0,m1;
uint8_t idx=0;
AssertFatal(symbol>=0 && symbol <3,"illegal symbol %d\n",symbol);
if (symbol == 0) {
m0=0;
m1=60;
}
else if (symbol == 1) {
m0=60;
m1=84;
}
else {
m0=84;
m1=144;
if (sidelink) {
AssertFatal(symbol== 0 || (symbol>=5 && symbol <=12),"illegal symbol %d\n",symbol);
m0 = (symbol) ? (symbol - 4) * 33 : 0;
m1 = (symbol) ? (symbol - 3) * 33 : 33;
} else {
AssertFatal(symbol>=0 && symbol <3,"illegal symbol %d\n",symbol);
if (symbol == 0) {
m0=0;
m1=60;
}
else if (symbol == 1) {
m0=60;
m1=84;
}
else {
m0=84;
m1=144;
}
}
// printf("Generating pilots symbol %d, m0 %d, m1 %d\n",symbol,m0,m1);
/// QPSK modulation
+64
View File
@@ -20,6 +20,7 @@
*/
#include "refsig_defs_ue.h"
#include "PHY/NR_REFSIG/nr_mod_table.h"
void nr_gold_pbch(PHY_VARS_NR_UE* ue)
{
@@ -148,3 +149,66 @@ void init_nr_gold_prs(PHY_VARS_NR_UE* ue)
} // for rsc
} // for gnb
}
void sl_init_psbch_dmrs_gold_sequences(PHY_VARS_NR_UE *UE)
{
unsigned int x1, x2;
uint16_t slss_id;
uint8_t reset;
for (slss_id = 0; slss_id < SL_NR_NUM_SLSS_IDs; slss_id++) {
reset = 1;
x2 = slss_id;
#ifdef SL_DEBUG_INIT
printf("\nPSBCH DMRS GOLD SEQ for SLSSID :%d :\n", slss_id);
#endif
for (uint8_t n=0; n<SL_NR_NUM_PSBCH_DMRS_RE_DWORD; n++) {
UE->SL_UE_PHY_PARAMS.init_params.psbch_dmrs_gold_sequences[slss_id][n] = lte_gold_generic(&x1, &x2, reset);
reset = 0;
#ifdef SL_DEBUG_INIT_DATA
printf("%x\n",SL_UE_INIT_PARAMS.sl_psbch_dmrs_gold_sequences[slss_id][n]);
#endif
}
}
}
void sl_generate_psbch_dmrs_qpsk_sequences(PHY_VARS_NR_UE *UE,
struct complex16 *modulated_dmrs_sym,
uint16_t slss_id)
{
uint8_t idx = 0;
uint32_t *sl_dmrs_sequence = UE->SL_UE_PHY_PARAMS.init_params.psbch_dmrs_gold_sequences[slss_id];
c16_t *mod_table = (c16_t *)nr_qpsk_mod_table;
#ifdef SL_DEBUG_INIT
printf("SIDELINK INIT: PSBCH DMRS Generation with slss_id:%d\n", slss_id);
#endif
/// QPSK modulation
for (int m=0; m<SL_NR_NUM_PSBCH_DMRS_RE; m++) {
idx = (((sl_dmrs_sequence[(m<<1)>>5])>>((m<<1)&0x1f))&3);
modulated_dmrs_sym[m].r = mod_table[idx].r;
modulated_dmrs_sym[m].i = mod_table[idx].i;
#ifdef SL_DEBUG_INIT_DATA
printf("m:%d gold seq: %d b0-b1: %d-%d DMRS Symbols: %d %d\n", m, sl_dmrs_sequence[(m<<1)>>5], (((sl_dmrs_sequence[(m<<1)>>5])>>((m<<1)&0x1f))&1),
(((sl_dmrs_sequence[((m<<1)+1)>>5])>>(((m<<1)+1)&0x1f))&1), modulated_dmrs_sym[m].r, modulated_dmrs_sym[m].i);
printf("idx:%d, qpsk_table.r:%d, qpsk_table.i:%d\n", idx, mod_table[idx].r, mod_table[idx].i);
#endif
}
#ifdef SL_DUMP_INIT_SAMPLES
char filename[40], varname[25];
sprintf(filename,"sl_psbch_dmrs_slssid_%d.m", slss_id);
sprintf(varname,"sl_dmrs_id_%d.m", slss_id);
LOG_M(filename, varname, (void*)modulated_dmrs_sym, SL_NR_NUM_PSBCH_DMRS_RE, 1, 1);
#endif
}
+11 -2
View File
@@ -30,7 +30,10 @@
/*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PBCH DMRS.
@param PHY_VARS_NR_UE* ue structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables
*/
void nr_pbch_dmrs_rx(const int dmrss, const unsigned int *nr_gold_pbch, c16_t *output);
void nr_pbch_dmrs_rx(int dmrss,
unsigned int *nr_gold_pbch,
c16_t *output,
bool sidelink);
/*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PDCCH DMRS.
@param PHY_VARS_NR_UE* ue structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables
@@ -66,5 +69,11 @@ void nr_init_pusch_dmrs(PHY_VARS_NR_UE* ue,
void nr_init_csi_rs(const NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid);
void init_nr_gold_prs(PHY_VARS_NR_UE* ue);
void sl_generate_pss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint8_t n_sl_id2, uint16_t scaling);
void sl_generate_pss_ifft_samples(sl_nr_ue_phy_params_t *sl_ue_params, SL_NR_UE_INIT_PARAMS_t *sl_init_params);
void sl_generate_sss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint16_t slss_id, uint16_t scaling);
void sl_init_psbch_dmrs_gold_sequences(PHY_VARS_NR_UE *UE);
void sl_generate_psbch_dmrs_qpsk_sequences(PHY_VARS_NR_UE *UE,
struct complex16 *modulated_dmrs_sym,
uint16_t slss_id);
#endif
+9
View File
@@ -67,8 +67,17 @@
#define PHASE_HYPOTHESIS_NUMBER (16)
#define INDEX_NO_PHASE_DIFFERENCE (3) /* this is for no phase shift case */
/************** FUNCTION ******************************************/
static const c16_t phase_nr[PHASE_HYPOTHESIS_NUMBER] = {
// {pi/3 ---- pi/3, -pi/3 ---- pi/3}
{16384, -28377}, {20173, -25821}, {23571, -22762}, {26509, -19260},
{28932, -15383}, {30791, -11207}, {32051, -6813}, {32687, -2286},
{32687, 2286}, {32051, 6813}, {30791, 11207}, {28932, 15383},
{26509, 19260}, {23571, 22762}, {20173, 25821}, {16384, 28377}
};
void init_context_sss_nr(int amp);
void free_context_sss_nr(void);
@@ -657,7 +657,7 @@ c32_t nr_pbch_dmrs_correlation(const PHY_VARS_NR_UE *ue,
// generate pilot
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
c16_t pilot[200] __attribute__((aligned(16)));
nr_pbch_dmrs_rx(dmrss, nr_gold_pbch, pilot);
nr_pbch_dmrs_rx(dmrss, (uint32_t *)nr_gold_pbch, pilot, false);
c32_t computed_val = {0};
for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
@@ -717,42 +717,70 @@ c32_t nr_pbch_dmrs_correlation(const PHY_VARS_NR_UE *ue,
}
int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
NR_DL_FRAME_PARMS *fp,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
struct complex16 dl_ch_estimates_time[][ue->frame_parms.ofdm_symbol_size],
struct complex16 dl_ch_estimates_time[][fp->ofdm_symbol_size],
const UE_nr_rxtx_proc_t *proc,
unsigned char symbol,
int dmrss,
uint8_t ssb_index,
uint8_t n_hf,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
c16_t rxdataF[][fp->samples_per_slot_wCP],
bool sidelink,
uint16_t Nid)
{
int Ns = proc->nr_slot_rx;
c16_t pilot[200] __attribute__((aligned(16)));
//int slot_pbch;
const int nushift = ue->frame_parms.Nid_cell % 4;
unsigned int ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
if (ssb_offset>= ue->frame_parms.ofdm_symbol_size) ssb_offset-=ue->frame_parms.ofdm_symbol_size;
uint8_t nushift = 0, lastsymbol = 0, num_rbs = 0;
uint32_t *gold_seq = NULL;
const int ch_offset = ue->frame_parms.ofdm_symbol_size * symbol;
if (sidelink) {
AssertFatal(dmrss >= 0 && dmrss < 3,
AssertFatal(dmrss == 0 || (dmrss >= 5 && dmrss <= 12),
"symbol %d is illegal for PSBCH DM-RS \n",
dmrss);
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
LOG_D(PHY,"PSBCH Channel Estimation SLSSID:%d\n", Nid);
gold_seq = sl_phy_params->init_params.psbch_dmrs_gold_sequences[Nid];
lastsymbol = 12;
num_rbs = SL_NR_NUM_PSBCH_RBS_IN_ONE_SYMBOL;
} else {
nushift = fp->Nid_cell%4;
AssertFatal(dmrss >= 0 && dmrss < 3,
"symbol %d is illegal for PBCH DM-RS \n",
dmrss);
const int symbol_offset = ue->frame_parms.ofdm_symbol_size * symbol;
gold_seq = ue->nr_gold_pbch[n_hf][ssb_index];
lastsymbol = 2;
num_rbs = 20;
}
unsigned int ssb_offset = fp->first_carrier_offset + fp->ssb_start_subcarrier;
if (ssb_offset>= fp->ofdm_symbol_size) ssb_offset-= fp->ofdm_symbol_size;
const int ch_offset = fp->ofdm_symbol_size*symbol;
const int symbol_offset = fp->ofdm_symbol_size*symbol;
const int k = nushift;
const c16_t *fl, *fm, *fr;
DEBUG_PBCH("PBCH Channel Estimation : gNB_id %d ch_offset %d, OFDM size %d, Ncp=%d, Ns=%d, k=%d symbol %d\n",
proc->gNB_id,
ch_offset,
ue->frame_parms.ofdm_symbol_size,
ue->frame_parms.Ncp,
Ns,
k,
symbol);
proc->gNB_id,
ch_offset,
fp->ofdm_symbol_size,
fp->Ncp,
Ns,
k,
symbol);
const c16_t *fl, *fm, *fr;
switch (k) {
case 0:
@@ -787,7 +815,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
idft_size_idx_t idftsizeidx;
switch (ue->frame_parms.ofdm_symbol_size) {
switch (fp->ofdm_symbol_size) {
case 128:
idftsizeidx = IDFT_128;
break;
@@ -835,19 +863,19 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
// generate pilot
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
nr_pbch_dmrs_rx(dmrss, ue->nr_gold_pbch[n_hf][ssb_index], pilot);
nr_pbch_dmrs_rx(dmrss,gold_seq, &pilot[0], sidelink);
for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
for (int aarx=0; aarx<fp->nb_antennas_rx; aarx++) {
int re_offset = ssb_offset;
c16_t *pil = pilot;
c16_t *rxF = &rxdataF[aarx][symbol_offset + k];
c16_t *dl_ch = &dl_ch_estimates[aarx][ch_offset];
memset(dl_ch, 0, sizeof(c16_t) * ue->frame_parms.ofdm_symbol_size);
memset(dl_ch, 0, sizeof(c16_t) * fp->ofdm_symbol_size);
DEBUG_PBCH("pbch ch est pilot RB_DL %d\n", ue->frame_parms.N_RB_DL);
DEBUG_PBCH("k %d, first_carrier %d\n", k, ue->frame_parms.first_carrier_offset);
DEBUG_PBCH("pbch ch est pilot RB_DL %d\n", fp->N_RB_DL);
DEBUG_PBCH("k %d, first_carrier %d\n", k, fp->first_carrier_offset);
// Treat first 2 pilots specially (left edge)
c16_t ch;
@@ -855,31 +883,31 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
DEBUG_PBCH("pilot 0: rxF= (%d,%d), ch= (%d,%d), pil=(%d,%d)\n", rxF[re_offset].r, rxF[re_offset].i, ch.r, ch.i, pil->r, pil->i);
multaddRealVectorComplexScalar(fl, ch, dl_ch, 16);
pil++;
re_offset = (re_offset + 4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
ch = c16mulShift(*pil, rxF[re_offset], 15);
DEBUG_PBCH("pilot 1: rxF= (%d,%d), ch= (%d,%d), pil=(%d,%d)\n", rxF[re_offset].r, rxF[re_offset].i, ch.r, ch.i, pil->r, pil->i);
multaddRealVectorComplexScalar(fm, ch, dl_ch, 16);
pil++;
re_offset = (re_offset + 4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
ch = c16mulShift(*pil, rxF[re_offset], 15);
DEBUG_PBCH("pilot 2: rxF= (%d,%d), ch= (%d,%d), pil=(%d,%d)\n", rxF[re_offset].r, rxF[re_offset].i, ch.r, ch.i, pil->r, pil->i);
multaddRealVectorComplexScalar(fr, ch, dl_ch, 16);
pil++;
re_offset = (re_offset + 4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
dl_ch += 24;
for (int pilot_cnt = 3; pilot_cnt < (3 * 20); pilot_cnt += 3) {
for (int pilot_cnt = 3; pilot_cnt < (3 * num_rbs); pilot_cnt += 3) {
// if (pilot_cnt == 30)
// rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k)];
// in 2nd symbol, skip middle REs (48 with DMRS, 144 for SSS, and another 48 with DMRS)
if (dmrss == 1 && pilot_cnt == 12) {
pilot_cnt=48;
re_offset = (re_offset + 144) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset + 144) % fp->ofdm_symbol_size;
dl_ch += 288;
}
ch = c16mulShift(*pil, rxF[re_offset], 15);
@@ -894,7 +922,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
multaddRealVectorComplexScalar(fl, ch, dl_ch, 16);
pil++;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
ch = c16mulShift(*pil, rxF[re_offset], 15);
DEBUG_PBCH("pilot %u: rxF= (%d,%d), ch= (%d,%d), pil=(%d,%d)\n",
pilot_cnt + 1,
@@ -906,7 +934,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
pil->i);
multaddRealVectorComplexScalar(fm, ch, dl_ch, 16);
pil++;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
ch = c16mulShift(*pil, rxF[re_offset], 15);
DEBUG_PBCH("pilot %u: rxF= (%d,%d), ch= (%d,%d), pil=(%d,%d)\n",
pilot_cnt + 2,
@@ -918,11 +946,11 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
pil->i);
multaddRealVectorComplexScalar(fr, ch, dl_ch, 16);
pil++;
re_offset = (re_offset + 4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
dl_ch += 12;
}
if( dmrss == 2) // update time statistics for last PBCH symbol
if( dmrss == lastsymbol) // update time statistics for last PBCH symbol
{
// do ifft of channel estimate
LOG_D(PHY,"Channel Impulse Computation Slot %d Symbol %d ch_offset %d\n", Ns, symbol, ch_offset);
@@ -933,13 +961,13 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
}
}
if (dmrss == 2)
if (!sidelink && dmrss == lastsymbol)
UEscopeCopy(ue,
pbchDlChEstimateTime,
(void *)dl_ch_estimates_time,
sizeof(c16_t),
ue->frame_parms.nb_antennas_rx,
ue->frame_parms.ofdm_symbol_size,
fp->nb_antennas_rx,
fp->ofdm_symbol_size,
0);
return(0);
+10 -2
View File
@@ -65,15 +65,18 @@ c32_t nr_pbch_dmrs_correlation(const PHY_VARS_NR_UE *ue,
const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
NR_DL_FRAME_PARMS *fp,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
struct complex16 dl_ch_estimates_time[][ue->frame_parms.ofdm_symbol_size],
struct complex16 dl_ch_estimates_time[][fp->ofdm_symbol_size],
const UE_nr_rxtx_proc_t *proc,
unsigned char symbol,
int dmrss,
uint8_t ssb_index,
uint8_t n_hf,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
c16_t rxdataF[][fp->samples_per_slot_wCP],
bool sidelink,
uint16_t Nid);
int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
@@ -137,5 +140,10 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue,
NR_UE_DLSCH_t dlsch[2]);
float_t get_nr_RSRP(module_id_t Mod_id,uint8_t CC_id,uint8_t gNB_index);
void nr_sl_psbch_rsrp_measurements(sl_nr_ue_phy_params_t *sl_phy_params,
NR_DL_FRAME_PARMS *fp,
c16_t rxdataF[][fp->samples_per_slot_wCP],
bool use_SSS);
/** @}*/
#endif
@@ -309,3 +309,57 @@ void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue,
ue->measurements.n0_power_tot_dB + 30 - 10 * log10(pow(2, 30)) - dB_fixed(ue->frame_parms.ofdm_symbol_size)
- ((int)rx_gain - (int)rx_gain_offset));
}
//PSBCH RSRP calculations according to 38.215 section 5.1.22
void nr_sl_psbch_rsrp_measurements(sl_nr_ue_phy_params_t *sl_phy_params,
NR_DL_FRAME_PARMS *fp,
c16_t rxdataF[][fp->samples_per_slot_wCP],
bool use_SSS)
{
SL_NR_UE_PSBCH_t *psbch_rx = &sl_phy_params->psbch;
uint8_t numsym = (fp->Ncp) ? SL_NR_NUM_SYMBOLS_SSB_EXT_CP
: SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
uint32_t re_offset = fp->first_carrier_offset + fp->ssb_start_subcarrier;
uint32_t rsrp = 0, num_re = 0;
LOG_D(PHY, "PSBCH RSRP MEAS: numsym:%d, re_offset:%d\n",numsym, re_offset);
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
//Calculate PSBCH RSRP based from DMRS REs
for (uint8_t symbol=0; symbol<numsym;) {
struct complex16 *rxF = &rxdataF[aarx][symbol*fp->ofdm_symbol_size];
for (int re=0;re<SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL;re++) {
if (re%4 == 0) { //DMRS RE
uint16_t offset = (re_offset + re) % fp->ofdm_symbol_size;
rsrp += c16amp2(rxF[offset]);
num_re++;
}
}
symbol = (symbol == 0) ? 5 : symbol+1;
}
}
if (use_SSS) {
//TBD...
//UE can decide between using only PSBCH DMRS or PSBCH DMRS and SSS for PSBCH RSRP computation.
//If needed this can be implemented. Reference Spec 38.215
}
psbch_rx->rsrp_dB_per_RE = 10*log10(rsrp / num_re);
psbch_rx->rsrp_dBm_per_RE = psbch_rx->rsrp_dB_per_RE +
30 - 10*log10(pow(2,30)) -
((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) -
dB_fixed(fp->ofdm_symbol_size);
LOG_I(PHY, "PSBCH RSRP (DMRS REs): numREs:%d RSRP :%d dB/RE ,RSRP:%d dBm/RE\n",
num_re, psbch_rx->rsrp_dB_per_RE, psbch_rx->rsrp_dBm_per_RE);
}
@@ -101,6 +101,7 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
for(int i=pbch_initial_symbol; i<pbch_initial_symbol+3;i++)
nr_pbch_channel_estimation(ue,
&ue->frame_parms,
estimateSz,
dl_ch_estimates,
dl_ch_estimates_time,
@@ -109,7 +110,9 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
i - pbch_initial_symbol,
ssb->i_ssb,
ssb->n_hf,
rxdataF);
rxdataF,
false,
frame_parms->Nid_cell);
stop_meas(&ue->dlsch_channel_estimation_stats);
fapiPbch_t result = {0};
@@ -0,0 +1,529 @@
#include "PHY/defs_nr_UE.h"
#include "PHY/TOOLS/tools_defs.h"
#include "PHY/NR_REFSIG/sss_nr.h"
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
#include "PHY/MODULATION/modulation_UE.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "SCHED_NR_UE/defs.h"
//Number of symbols carrying SLSS signal - PSS+SSS+PSBCH
#define SL_NR_NUMSYM_SLSS_NORMAL_CP 14
#define SL_NR_MAX_RX_ANTENNA 1
#define SL_NR_FIRST_PSS_SYMBOL 1
#define SL_NR_FIRST_SSS_SYMBOL 3
#define SL_NR_NUM_PSS_SSS_SYMBOLS 4
//#define SL_DEBUG
static int sl_nr_pss_correlation(PHY_VARS_NR_UE *UE, int frame_index)
{
sl_nr_ue_phy_params_t *sl_ue = &UE->SL_UE_PHY_PARAMS;
SL_NR_SYNC_PARAMS_t *sync_params = &sl_ue->sync_params;
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
int16_t **pss_for_correlation = (int16_t **)sl_ue->init_params.sl_pss_for_correlation;
uint32_t length = (frame_index == 0) ? sl_fp->samples_per_frame + (2 * sl_fp->ofdm_symbol_size) : sl_fp->samples_per_frame;
int32_t **rxdata = (int32_t **)UE->common_vars.rxdata;
#ifdef SL_DEBUG
char fname[50], sname[25];
sprintf(fname,"rxdata_frame_%d.m",frame_index);
sprintf(sname,"rxd_frame%d",frame_index);
LOG_M(fname,sname, &rxdata[0][frame_index * sl_fp->samples_per_frame],sl_fp->samples_per_frame,1,1);
LOG_M("pss_for_correlation0.m","pss_id0", pss_for_correlation[0],2048,1,1);
LOG_M("pss_for_correlation1.m","pss_id1", pss_for_correlation[1],2048,1,1);
int64_t *pss_corr_debug_values[SL_NR_NUM_IDs_IN_PSS];
#endif
int maxval=0;
for (int i=0;i<2*(sl_fp->ofdm_symbol_size);i++) {
maxval = max(maxval,pss_for_correlation[0][i]);
maxval = max(maxval,-pss_for_correlation[0][i]);
maxval = max(maxval,pss_for_correlation[1][i]);
maxval = max(maxval,-pss_for_correlation[1][i]);
}
int shift = log2_approx(maxval);//*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples)*2);
#ifdef SL_DEBUG
LOG_I(PHY,"SIDELINK SLSS SEARCH: Function:%s\n", __func__);
LOG_I(PHY,"maxval:%d, shift:%d\n", maxval, shift);
#endif
int64_t avg[SL_NR_NUM_IDs_IN_PSS] = {0};
int64_t peak_value = 0, psss_corr_value = 0;
unsigned int peak_position = 0, pss_source = 0;
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++)
avg[pss_index]=0;
#ifdef SL_DEBUG
int64_t *pss_corr_debug_values[SL_NR_NUM_IDs_IN_PSS];
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++)
pss_corr_debug_values[pss_index] = malloc16_clear(length*sizeof(int64_t));
#endif
for (int n=0; n < length - sl_fp->ofdm_symbol_size; n+=4) { //
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++) {
psss_corr_value = 0;
// calculate dot product of primary_synchro_time_nr and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
for (int ar=0; ar<sl_fp->nb_antennas_rx; ar++) {
/* perform correlation of rx data and pss sequence ie it is a dot product */
const c32_t result = dot_product((c16_t *)pss_for_correlation[pss_index],
(c16_t *)&(rxdata[ar][n + frame_index * sl_fp->samples_per_frame]),
sl_fp->ofdm_symbol_size,
shift);
const c64_t r64 = {.r = result.r, .i = result.i};
psss_corr_value += squaredMod(r64);
#ifdef SL_DEBUG
pss_corr_debug_values[pss_index][n] = psss_corr_value;
printf("frame:%d n:%d, pss_index:%d, pss_for_correlation[pss_index][0]:%x, rxdata[n]:%x\n",
frame_index, n, pss_index, pss_for_correlation[pss_index][0], rxdata[ar][n + frame_index * sl_fp->samples_per_frame]);
printf("result %lld, pss_corr_values[%d][%d]:%ld\n",result, pss_index, n, pss_corr_debug_values[pss_index][n]);
printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)pss_corr_debug_values[pss_index][n]);
printf("peak_value:%ld, peak_position:%d, pss_source:%d\n", peak_value, peak_position, pss_source);
#endif
}
// calculate the absolute value of sync_corr[n]
avg[pss_index] += psss_corr_value;
if (psss_corr_value > peak_value) {
peak_value = psss_corr_value;
peak_position = n;
pss_source = pss_index;
#ifdef SL_DEBUG
printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)psss_corr_value);
#endif
}
}
}
#ifdef SL_DEBUG
LOG_M("pss_corr_debug_values_0.m","pss_corr0", &pss_corr_debug_values[0][0],length,1,6);
LOG_M("pss_corr_debug_values_1.m","pss_corr1", &pss_corr_debug_values[1][0],length,1,6);
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++) {
free(pss_corr_debug_values[pss_index]);
}
#endif
double ffo_est=0;
if (UE->UE_fo_compensation) { // Not tested
// fractional frequency offset computation according to Cross-correlation Synchronization Algorithm Using PSS
// Shoujun Huang, Yongtao Su, Ying He and Shan Tang, "Joint time and frequency offset estimation in LTE downlink," 7th International Conference on Communications and Networking in China, 2012.
c16_t *pss = (c16_t *)pss_for_correlation[pss_source];
c16_t *rxd = (c16_t *)&(rxdata[0][peak_position + frame_index * sl_fp->samples_per_frame]);
int half_symbol = sl_fp->ofdm_symbol_size>>1;
// Computing cross-correlation at peak on half the symbol size for first half of data
c32_t r1 = dot_product(pss, rxd, half_symbol, shift);
// Computing cross-correlation at peak on half the symbol size for data shifted by half symbol size
// as it is real and complex it is necessary to shift by a value equal to symbol size to obtain such shift
c32_t r2 = dot_product(pss + half_symbol, rxd + half_symbol, half_symbol, shift);
cd_t r1d = {r1.r, r1.i}, r2d = {r2.r, r2.i};
// estimation of fractional frequency offset: angle[(result1)'*(result2)]/pi
ffo_est = atan2(r1d.r * r2d.i - r2d.r * r1d.i, r1d.r * r2d.r + r1d.i * r2d.i) / M_PI;
#ifdef SL_DEBUG
printf("ffo %lf\n",ffo_est);
#endif
}
// computing absolute value of frequency offset
sync_params->freq_offset = ffo_est*sl_fp->subcarrier_spacing;
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++) avg[pss_index]/=(length/4);
sync_params->N_sl_id2 = pss_source;
LOG_I(PHY,"PSS Source = %d, Peak found at pos %d, val = %llu (%d dB) avg %d dB, ffo %lf, freq offset:%d Hz\n",
pss_source, peak_position, (unsigned long long)peak_value, dB_fixed64(peak_value),dB_fixed64(avg[pss_source]),ffo_est, sync_params->freq_offset);
if (peak_value < 5*avg[pss_source])
return(-1);
return peak_position;
}
static void sl_nr_extract_sss(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc,
int32_t *tot_metric, uint8_t *phase_max,
c16_t rxdataF[][ue->SL_UE_PHY_PARAMS.sl_frame_params.samples_per_slot_wCP])
{
c16_t pss_ext[SL_NR_MAX_RX_ANTENNA][SL_NR_NUM_PSS_SYMBOLS][SL_NR_PSS_SEQUENCE_LENGTH];
c16_t sss_ext[SL_NR_MAX_RX_ANTENNA][SL_NR_NUM_SSS_SYMBOLS][SL_NR_PSS_SEQUENCE_LENGTH];
uint8_t Nid2 = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2;
NR_DL_FRAME_PARMS *sl_fp=&ue->SL_UE_PHY_PARAMS.sl_frame_params;
int16_t *d;
uint16_t Nid1 = 0;
uint8_t phase;
c16_t *rxF_ext;
for (int aarx=0; aarx < sl_fp->nb_antennas_rx; aarx++) {
unsigned int ofdm_symbol_size = sl_fp->ofdm_symbol_size;
// pss, sss extraction
for (int sym = SL_NR_FIRST_PSS_SYMBOL; sym < SL_NR_FIRST_PSS_SYMBOL + SL_NR_NUM_PSS_SSS_SYMBOLS;sym ++) {
if (sym < SL_NR_FIRST_PSS_SYMBOL + SL_NR_NUM_PSS_SYMBOLS) {
rxF_ext = &pss_ext[aarx][sym-SL_NR_FIRST_PSS_SYMBOL][0];
} else {
rxF_ext = &sss_ext[aarx][sym-SL_NR_FIRST_SSS_SYMBOL][0];
}
unsigned int k = sl_fp->first_carrier_offset + sl_fp->ssb_start_subcarrier + 2;
if (k >= ofdm_symbol_size) k -= ofdm_symbol_size;
LOG_D(PHY, "firstcarrieroffset:%d, ssb_sc:%d, k:%d, symbol:%d\n",sl_fp->first_carrier_offset, sl_fp->ssb_start_subcarrier, k, sym);
for (int i=0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
rxF_ext[i] = rxdataF[aarx][sym*ofdm_symbol_size + k];
k++;
if (k == ofdm_symbol_size) k=0;
}
}
LOG_D(PHY, "SIDELINK SLSS SEARCH: EXTRACTION OF PSS, SSS done\n");
#ifdef SL_DEBUG
LOG_M("pss_ext_sym1.m","pss_ext1",&pss_ext[aarx][0][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
LOG_M("pss_ext_sym2.m","pss_ext2",&pss_ext[aarx][1][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
LOG_M("sss_ext_sym3.m","sss_ext3",&sss_ext[aarx][0][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
LOG_M("sss_ext_sym4.m","sss_ext4",&sss_ext[aarx][1][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
#endif
// get conjugated channel estimate from PSS, H* = R* \cdot PSS
// and do channel estimation and compensation based on PSS
int16_t *pss = ue->SL_UE_PHY_PARAMS.init_params.sl_pss_for_sync[Nid2];
c16_t *pss_ext2,*sss_ext2;
//2 Symbols each for PSS and SSS
for (int j=0; j<SL_NR_NUM_PSS_OR_SSS_SYMBOLS;j++) {
sss_ext2 = &sss_ext[aarx][j][0];
pss_ext2 = &pss_ext[aarx][j][0];
for (int i = 0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
// This is H*(PSS) = R* \cdot PSS
c16_t tmp = {.r = (pss_ext2[i].r * pss[i]), .i = (-pss_ext2[i].i * pss[i])};
int amp = c16amp2(tmp);
int shift = log2_approx(amp)/2;
// This is R(SSS) \cdot H*(PSS)
c16_t tmp2 = c16mulShift(tmp, sss_ext2[i], shift);
// MRC on RX antennas
// sss_ext now contains the compensated SSS
if (aarx==0) {
sss_ext2[i].r = tmp2.r;
sss_ext2[i].i = tmp2.i;
} else {
AssertFatal(1==0,"SIDELINK MORE THAN 1 RX ANTENNA NOT YET SUPPORTED\n");
}
}
}
LOG_D(PHY, "SIDELINK SLSS SEARCH: Ch. estimation SSS done\n");
}
/*
#ifdef SL_DEBUG
write_output("rxsig0.m","rxs0",&ue->common_vars.rxdata[0][0],ue->frame_parms.samples_per_subframe,1,1);
write_output("rxdataF0_pss.m","rxF0_pss",&ue->common_vars.rxdataF[0][0],frame_parms->ofdm_symbol_size,1,1);
write_output("rxdataF0_sss.m","rxF0_sss",&ue->common_vars.rxdataF[0][(SSS_SYMBOL_NB-PSS_SYMBOL_NB)*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1);
write_output("pss_ext.m","pss_ext",pss_ext,LENGTH_PSS_NR,1,1);
#endif
*/
/* for phase evaluation, one uses an array of possible phase shifts */
/* then a correlation is done between received signal with a shift pĥase and the reference signal */
/* Computation of signal with shift phase is based on below formula */
/* cosinus cos(x + y) = cos(x)cos(y) - sin(x)sin(y) */
/* sinus sin(x + y) = sin(x)cos(y) + cos(x)sin(y) */
// now do the SSS detection based on the pre computed SSS sequences
*tot_metric = INT_MIN;
c16_t *sss = &sss_ext[0][0][0];
for (uint16_t id1 = 0 ; id1 < SL_NR_NUM_IDs_IN_SSS; id1++) { // all possible SSS Nid1 values
for (phase=0; phase < PHASE_HYPOTHESIS_NUMBER; phase++) { // phase offset between PSS and SSS
int32_t metric = 0, metric_re = 0;
d = (int16_t *)&ue->SL_UE_PHY_PARAMS.init_params.sl_sss_for_sync[Nid2 * SL_NR_NUM_IDs_IN_SSS + id1];
// This is the inner product using one particular value of each unknown parameter
for (int i=0; i < SL_NR_SSS_SEQUENCE_LENGTH; i++) {
metric_re += d[i] * (((int64_t) phase_nr[phase].r * sss[i].r - phase_nr[phase].i * sss[i].i) >> 15);
}
metric = metric_re;
// if the current metric is better than the last save it
if (metric > *tot_metric) {
*tot_metric = metric;
Nid1 = id1;
*phase_max = phase;
LOG_D(PHY, "(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",
phase, Nid1, metric, *tot_metric, *phase_max);
}
}
}
ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1 = Nid1;
ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1 +
SL_NR_NUM_IDs_IN_SSS * ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2;
LOG_I(PHY, "UE[%d]NR-SL SLSS SEARCH: SSS Processing over. id2 from SSS:%d, id1 from PSS:%d, SLSS id:%d\n",
ue->Mod_id, ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1, ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2,
ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id);
#ifdef SL_DEBUG
#define SSS_METRIC_FLOOR_NR (30000)
if (*tot_metric > SSS_METRIC_FLOOR_NR) {
Nid2 = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2;
Nid1 = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1;
printf("Nid2 %d Nid1 %d tot_metric %d, phase_max %d \n", Nid2, Nid1, *tot_metric, *phase_max);
}
#endif
return;
}
// Right now 2 frames worth of samples get processed for PSS in OAI.
// For PSS in Sidelink, worst case 1 SSB in 16 frames can be present
// Hence 16 frames worth of samples needs to be correlated to find the PSS.
nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, int num_frames)
{
sl_nr_ue_phy_params_t *sl_ue = &UE->SL_UE_PHY_PARAMS;
SL_NR_SYNC_PARAMS_t *sync_params = &sl_ue->sync_params;
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
int32_t sync_pos = -1;// sync_pos_frame = -1;
int32_t metric_tdd_ncp=0;
uint8_t phase_tdd_ncp;
double im, re;
int ret=-1;
uint16_t rx_slss_id = 65535;
nr_initial_sync_t result = {true, 0};
#ifdef SL_DEBUG_SEARCH_SLSS
LOG_D(PHY, "SIDELINK SEARCH SLSS: Function:%s\n", __func__);
#endif
/* Initial synchronisation
*
* 1 radio frame = 10 ms
* <--------------------------------------------------------------------------->
* | Received UE data buffer |
* ----------------------------------------------------------------------------
* <-------------->|psbch|pss|pss|sss|sss|psbch sym5-sym 12|sym13 - guard|
* sync_pos SS/PSBCH block
*/
// initial sync performed on 16 successive frames. Worst case - one PSBCH can be sent in 16 frames.
//If psbch passes on first frame, no need to process second frame
// Problem with the frame approach is that
// --------- SSB can be on the boundary between frames. In this case if only 1 SSB is sent we will miss it.
// rxdata will hold 16 frames + slot worth of samples. This needs to be processed to find the best SSB
for(int frame_index = 0; frame_index < num_frames; frame_index++) {
/* process pss search on received buffer */
sync_pos = sl_nr_pss_correlation(UE, frame_index);
if (sync_pos == -1) {
LOG_I(PHY,"SIDELINK SEARCH SLSS: No PSSS found in this frame\n");
continue;
}
sync_pos += frame_index * sl_fp->samples_per_frame; // position in the num_frames frame samples
for (int pss_sym = 1; pss_sym < 3;pss_sym++) {
// Now Sync pos can point to PSS 1st symbol or 2nd symbol.
// Right now implemented the strategy to try both locations for FFT
// Think about a better correlation strategy
if (pss_sym == 1) { // Check if sync pos points to SYMBOL1 - first symbol of PSS location
if (sync_pos > sl_fp->nb_prefix_samples0 + sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples)
sync_params->ssb_offset = sync_pos - (sl_fp->nb_prefix_samples0 + sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples);
else
sync_params->ssb_offset = sync_pos + sl_fp->samples_per_frame - (sl_fp->nb_prefix_samples0 + sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples);
} else { // Check if sync pos points to SYMBOL2 - second symbol of PSS location
if (sync_pos >= sl_fp->nb_prefix_samples0 + 2*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples))
sync_params->ssb_offset = sync_pos - (sl_fp->nb_prefix_samples0 + 2*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples));
else
sync_params->ssb_offset = sync_pos + sl_fp->samples_per_frame - (sl_fp->nb_prefix_samples0 + 2*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples));
}
LOG_I(PHY,"UE[%d]SIDELINK SEARCH SLSS: PSS Peak at %d, PSS sym:%d, Estimated PSS position %d\n",
UE->Mod_id,sync_pos,pss_sym,sync_params->ssb_offset);
int slss_block_samples = (SL_NR_NUMSYM_SLSS_NORMAL_CP * sl_fp->ofdm_symbol_size) +
(SL_NR_NUMSYM_SLSS_NORMAL_CP -1) * sl_fp->nb_prefix_samples + sl_fp->nb_prefix_samples0;
int ssb_end_position = sync_params->ssb_offset + slss_block_samples;
LOG_D(PHY, "ssb_end:%d ssb block samples:%d total samples: %d\n", ssb_end_position, slss_block_samples, num_frames * sl_fp->samples_per_frame);
/* check that SSS/PBCH block is continuous inside the received buffer */
if (ssb_end_position < num_frames * sl_fp->samples_per_frame) {
// digital compensation of FFO for SSB symbols
if (UE->UE_fo_compensation){ // This code to be checked. Why do we do this before PSS detection is successful?
double s_time = 1/(1.0e3 * sl_fp->samples_per_subframe); // sampling time
double off_angle = -2 * M_PI * s_time * (sync_params->freq_offset); // offset rotation angle compensation per sample
int start = sync_params->ssb_offset; // start for offset correction is at ssb_offset (pss time position)
// Adapt this for other numerologies number of symbols with larger cp increases TBD
int end = ssb_end_position; // loop over samples in all symbols (ssb size), including prefix
LOG_I(PHY,"SLSS SEARCH: FREQ comp of SLSS samples. Freq_OFSET:%d, startpos:%d, end_pos:%d\n",
sync_params->freq_offset, start, end);
for(int n=start; n<end; n++) {
for (int ar=0; ar<sl_fp->nb_antennas_rx; ar++) {
re = ((double)(((short *)UE->common_vars.rxdata[ar]))[2*n]);
im = ((double)(((short *)UE->common_vars.rxdata[ar]))[2*n+1]);
((short *)UE->common_vars.rxdata[ar])[2*n] = (short)(round(re*cos(n*off_angle) - im*sin(n*off_angle)));
((short *)UE->common_vars.rxdata[ar])[2*n+1] = (short)(round(re*sin(n*off_angle) + im*cos(n*off_angle)));
}
}
}
NR_DL_FRAME_PARMS *frame_parms = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
const uint32_t rxdataF_sz = frame_parms->samples_per_slot_wCP;
__attribute__ ((aligned(32))) c16_t rxdataF[frame_parms->nb_antennas_rx][rxdataF_sz];
/* In order to achieve correct processing for NR prefix samples is forced to 0 and then restored after function call */
for(int symbol=0; symbol<SL_NR_NUMSYM_SLSS_NORMAL_CP;symbol++) {
sl_nr_slot_fep(UE,
NULL,
symbol,
0,
sync_params->ssb_offset,
rxdataF);
}
sl_nr_extract_sss(UE, NULL, &metric_tdd_ncp, &phase_tdd_ncp, rxdataF);
// save detected cell id to psbch
rx_slss_id = UE->SL_UE_PHY_PARAMS.sync_params.N_sl_id;
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates[frame_parms->nb_antennas_rx][rxdataF_sz];
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size];
uint8_t decoded_output[4];
for (int symbol = 0; symbol < SL_NR_NUMSYM_SLSS_NORMAL_CP-1;) {
nr_pbch_channel_estimation(UE,
frame_parms,
rxdataF_sz,
dl_ch_estimates,
dl_ch_estimates_time,
proc,
symbol,
symbol,
0,
0,
rxdataF,
1,
rx_slss_id);
symbol = (symbol == 0) ? 5 : symbol+1;
}
ret = nr_rx_psbch(UE,proc,
rxdataF_sz,
dl_ch_estimates,
frame_parms,
decoded_output,
rxdataF,
rx_slss_id);
result.cell_detected = (ret == 0) ? true : false;
if (result.cell_detected) { // Check this later TBD
// sync at symbol ue->symbol_offset
// computing the offset wrt the beginning of the frame
// SSB located at symbol 0
sync_params->remaining_frames = (num_frames * sl_fp->samples_per_frame - sync_params->ssb_offset)/sl_fp->samples_per_frame;
//ssb_offset points to start of sl-ssb
//rx_offset points to remaining samples needed to fill a frame
sync_params->rx_offset = sync_params->ssb_offset % sl_fp->samples_per_frame;
LOG_I(PHY,"UE[%d]SIDELINK SLSS SEARCH: PSBCH RX OK. Remainingframes:%d, rx_offset:%d\n",
UE->Mod_id,sync_params->remaining_frames, sync_params->rx_offset);
uint32_t psbch_payload = (*(uint32_t *)decoded_output);
//retrieve DFN and slot number from SL-MIB
sync_params->DFN = (((psbch_payload & 0x0700) >> 1) | ((psbch_payload & 0xFE0000) >> 17));
sync_params->slot_offset = (((psbch_payload & 0x010000) >> 10) | ((psbch_payload & 0xFC000000) >> 26));
LOG_I(PHY, "UE[%d]SIDELINK SLSS SEARCH: SL-MIB: DFN:%d, slot:%d.\n",
UE->Mod_id, sync_params->DFN, sync_params->slot_offset);
nr_sl_psbch_rsrp_measurements(sl_ue,frame_parms,rxdataF, false);
UE->init_sync_frame = sync_params->remaining_frames;
result.rx_offset = sync_params->rx_offset;
nr_sidelink_indication_t sl_indication;
sl_nr_rx_indication_t rx_ind = {0};
uint16_t number_pdus = 1;
nr_fill_sl_indication(&sl_indication, &rx_ind, NULL, proc, UE, NULL);
nr_fill_sl_rx_indication(&rx_ind, SL_NR_RX_PDU_TYPE_SSB, UE, number_pdus, proc, (void *)decoded_output, rx_slss_id);
LOG_D(PHY,"Sidelink SLSS SEARCH PSBCH RX OK. Send SL-SSB TO MAC\n");
if (UE->if_inst && UE->if_inst->sl_indication)
UE->if_inst->sl_indication(&sl_indication);
break;
}
LOG_I(PHY,"SIDELINK SLSS SEARCH: SLSS ID: %d metric %d, phase %d, psbch CRC %s\n",
sl_ue->sync_params.N_sl_id,metric_tdd_ncp,phase_tdd_ncp,(ret == 0) ? "OK" : "NOT OK");
} else {
LOG_W(PHY,"SIDELINK SLSS SEARCH: Error: Not enough samples to process PSBCH. sync_pos %d\n", sync_pos);
}
}
if (result.cell_detected) break;
}
if (!result.cell_detected) { // PSBCH not found so indicate sync to higher layers and configure frame parameters
LOG_E(PHY,"SIDELINK SLSS SEARCH: PSBCH not received. Estimated PSS position:%d\n", sync_pos);
}
return result;
}
+10 -12
View File
@@ -45,7 +45,6 @@
//#include "PHY_INTERFACE/defs.h"
#define PBCH_A 24
#define PBCH_MAX_RE_PER_SYMBOL (20*12)
#define PBCH_MAX_RE (PBCH_MAX_RE_PER_SYMBOL*4)
#define print_shorts(s,x) printf("%s : %d,%d,%d,%d,%d,%d,%d,%d\n",s,((int16_t*)x)[0],((int16_t*)x)[1],((int16_t*)x)[2],((int16_t*)x)[3],((int16_t*)x)[4],((int16_t*)x)[5],((int16_t*)x)[6],((int16_t*)x)[7])
@@ -230,20 +229,19 @@ int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER
return(avg2);
}
static void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
int nb_re,
struct complex16 rxdataF_comp[][PBCH_MAX_RE_PER_SYMBOL],
NR_DL_FRAME_PARMS *frame_parms,
uint8_t output_shift) {
void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
int nb_re,
struct complex16 rxdataF_comp[][PBCH_MAX_RE_PER_SYMBOL],
NR_DL_FRAME_PARMS *frame_parms,
uint8_t output_shift)
{
for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[aarx];
simde__m128i *rxdataF128 = (simde__m128i *)rxdataF_ext[aarx];
simde__m128i *rxdataF_comp128 = (simde__m128i *)rxdataF_comp[aarx];
for (int re=0; re<nb_re; re+=12) {
*rxdataF_comp128++ = mulByConjugate128(rxdataF128++, dl_ch128++, output_shift);
*rxdataF_comp128++ = mulByConjugate128(rxdataF128++, dl_ch128++, output_shift);
for (int re=0; re<nb_re; re+=4) {
*rxdataF_comp128++ = mulByConjugate128(rxdataF128++, dl_ch128++, output_shift);
}
}
@@ -272,7 +270,7 @@ void nr_pbch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms,
simde_m_empty();
}
static void nr_pbch_unscrambling(int16_t *demod_pbch_e,
void nr_pbch_unscrambling(int16_t *demod_pbch_e,
uint16_t Nid,
uint8_t nushift,
uint16_t M,
@@ -334,7 +332,7 @@ static void nr_pbch_unscrambling(int16_t *demod_pbch_e,
}
}
static void nr_pbch_quantize(int16_t *pbch_llr8,
void nr_pbch_quantize(int16_t *pbch_llr8,
int16_t *pbch_llr,
uint16_t len) {
for (int i=0; i<len; i++) {
+235
View File
@@ -0,0 +1,235 @@
/*
* 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
*/
#include "PHY/defs_nr_UE.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
#include "common/utils/LOG/log.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
//#define DEBUG_PSBCH
static void nr_psbch_extract(uint32_t rxdataF_sz,
c16_t rxdataF[][rxdataF_sz],
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
struct complex16 rxdataF_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
struct complex16 dl_ch_estimates_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
uint32_t symbol,
NR_DL_FRAME_PARMS *frame_params)
{
uint16_t rb;
uint8_t i,j,aarx;
struct complex16 *dl_ch0,*dl_ch0_ext,*rxF,*rxF_ext;
const uint8_t nb_rb = SL_NR_NUM_PSBCH_RBS_IN_ONE_SYMBOL;
AssertFatal((symbol == 0 || symbol >= 5), "SIDELINK: PSBCH DMRS not contained in symbol %d \n", symbol);
for (aarx=0; aarx<frame_params->nb_antennas_rx; aarx++) {
unsigned int rx_offset = frame_params->first_carrier_offset + frame_params->ssb_start_subcarrier;
rx_offset = rx_offset % frame_params->ofdm_symbol_size;
rxF = &rxdataF[aarx][symbol*frame_params->ofdm_symbol_size];
rxF_ext = &rxdataF_ext[aarx][0];
dl_ch0 = &dl_ch_estimates[aarx][symbol*frame_params->ofdm_symbol_size];
dl_ch0_ext = &dl_ch_estimates_ext[aarx][0];
#ifdef DEBUG_PSBCH
LOG_I(PHY, "extract_rbs: rx_offset=%d, symbol %u\n", (rx_offset + (symbol*frame_params->ofdm_symbol_size)),symbol);
#endif
for (rb=0; rb<nb_rb; rb++) {
j=0;
for (i=0; i<NR_NB_SC_PER_RB; i++) {
if (i%4 != 0) {
rxF_ext[j]=rxF[rx_offset];
dl_ch0_ext[j]=dl_ch0[i];
#ifdef DEBUG_PSBCH
LOG_I(PHY,"rxF ext[%d] = (%d,%d) rxF [%u]= (%d,%d)\n",
(9*rb) + j,rxF_ext[j].r,rxF_ext[j].i,
rx_offset,rxF[rx_offset].r,rxF[rx_offset].i);
LOG_I(PHY,"dl ch0 ext[%d] = (%d,%d) dl_ch0 [%d]= (%d,%d)\n",
(9*rb) + j,dl_ch0_ext[j].r,dl_ch0_ext[j].i,
i, dl_ch0[i].r,dl_ch0[i].i);
#endif
j++;
}
rx_offset=(rx_offset+1)%(frame_params->ofdm_symbol_size);
}
rxF_ext += SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_RB;
dl_ch0_ext += SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_RB;
dl_ch0 += NR_NB_SC_PER_RB;
}
#ifdef DEBUG_PSBCH
char filename[40], varname[25];
sprintf(filename,"psbch_dlch_sym_%d.m", symbol);
sprintf(varname,"psbch_dlch%d.m", symbol);
LOG_M(filename, varname, (void*)dl_ch0, frame_params->ofdm_symbol_size, 1, 1);
sprintf(filename,"psbch_dlchext_sym_%d.m", symbol);
sprintf(varname,"psbch_dlchext%d.m", symbol);
LOG_M(filename, varname, (void*)&dl_ch_estimates_ext[0][0], SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL , 1, 1);
#endif
}
return;
}
int nr_rx_psbch(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
NR_DL_FRAME_PARMS *frame_parms,
uint8_t *decoded_output,
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
uint16_t slss_id)
{
uint32_t decoderState=0;
int psbch_e_rx_idx = 0;
//Extra 2 bits needed as polar decoder expects a multiple of 4 as encoder length
//If these 2 bits are not added, runs compiled with --sanitize will fail.
int16_t psbch_e_rx[SL_NR_POLAR_PSBCH_E_NORMAL_CP+2]= {0};
#ifdef DEBUG_PSBCH
write_output("psbch_rxdataF.m","psbchrxF",
&rxdataF[0][0],frame_parms->ofdm_symbol_size*SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP,1,1);
#endif
// symbol refers to symbol within SSB. symbol_offset is the offset of the SSB wrt start of slot
double log2_maxh = 0;
// 0 for Normal Cyclic Prefix and 1 for EXT CyclicPrefix
const int numsym = (frame_parms->Ncp) ? SL_NR_NUM_SYMBOLS_SSB_EXT_CP
: SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
for (int symbol=0; symbol<numsym;) {
const uint16_t nb_re = SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL;
__attribute__ ((aligned(32))) struct complex16 rxdataF_ext[frame_parms->nb_antennas_rx][nb_re+1];
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_ext[frame_parms->nb_antennas_rx][nb_re+1];
//memset(dl_ch_estimates_ext,0, sizeof dl_ch_estimates_ext);
nr_psbch_extract(frame_parms->samples_per_slot_wCP,
rxdataF,
estimateSz,
dl_ch_estimates,
rxdataF_ext,
dl_ch_estimates_ext,
symbol,
frame_parms);
#ifdef DEBUG_PSBCH
LOG_I(PHY,"PSBCH RX Symbol %d ofdm size %d\n",symbol, frame_parms->ofdm_symbol_size );
#endif
int max_h=0;
if (symbol == 0) {
max_h = nr_pbch_channel_level(dl_ch_estimates_ext,
frame_parms,
nb_re);
//log2_maxh = 3+(log2_approx(max_h)/2);
log2_maxh = 5 +(log2_approx(max_h)/2);// LLR32 crc error. LLR 16 CRC works
}
#ifdef DEBUG_PSBCH
LOG_I(PHY,"PSBCH RX log2_maxh = %f (%d)\n", log2_maxh, max_h);
#endif
__attribute__ ((aligned(32))) struct complex16 rxdataF_comp[frame_parms->nb_antennas_rx][nb_re+1];
nr_pbch_channel_compensation(rxdataF_ext,
dl_ch_estimates_ext,
nb_re,
rxdataF_comp,
frame_parms,
log2_maxh); // log2_maxh+I0_shift
nr_pbch_quantize(psbch_e_rx + psbch_e_rx_idx,
(short *)rxdataF_comp[0],
SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL);
psbch_e_rx_idx += SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL;
//SKIP 2 SL-PSS AND 2 SL-SSS symbols
//Symbols carrying PSBCH 0, 5-12
symbol = (symbol == 0) ? 5 : symbol + 1;
}
#if 0 //ENABLE SCOPE LATER
UEscopeCopy(ue, psbchRxdataF_comp, psbch_unClipped, sizeof(struct complex16), frame_parms->nb_antennas_rx, psbch_e_rx_idx/2);
UEscopeCopy(ue, psbchLlr, psbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, psbch_e_rx_idx);
#endif
#ifdef DEBUG_PSBCH
write_output("psbch_rxdataFcomp.m","psbch_rxFcomp",psbch_unClipped,SL_NR_NUM_PSBCH_DATA_RE_IN_ALL_SYMBOLS,1,1);
#endif
//un-scrambling
LOG_D(PHY, "PSBCH RX POLAR DECODING: total PSBCH bits:%d, rx_slss_id:%d\n", psbch_e_rx_idx, slss_id);
nr_pbch_unscrambling(psbch_e_rx, slss_id, 0, 0, psbch_e_rx_idx,
0, 0, 0, NULL);
//polar decoding de-rate matching
uint64_t tmp=0;
decoderState = polar_decoder_int16(psbch_e_rx,(uint64_t *)&tmp,0,
SL_NR_POLAR_PSBCH_MESSAGE_TYPE, SL_NR_POLAR_PSBCH_PAYLOAD_BITS, SL_NR_POLAR_PSBCH_AGGREGATION_LEVEL);
uint32_t psbch_payload = tmp;
if(decoderState) {
LOG_D(PHY,"%d:%d PSBCH RX: NOK \n",proc->frame_rx, proc->nr_slot_rx);
return(decoderState);
}
// Decoder reversal
uint32_t a_reversed=0;
for (int i=0; i<SL_NR_POLAR_PSBCH_PAYLOAD_BITS; i++)
a_reversed |= (((uint64_t)psbch_payload>>i)&1)<<(31-i);
psbch_payload = a_reversed;
*((uint32_t *)decoded_output) = psbch_payload;
#ifdef DEBUG_PSBCH
for (int i=0; i<4; i++) {
LOG_I(PHY, "decoded_output[%d]:%x\n", i, decoded_output[i]);
}
#endif
ue->symbol_offset = 0;
//retrieve DFN and slot number from SL-MIB
uint32_t DFN = 0, slot_offset = 0;
DFN = (((psbch_payload & 0x0700) >> 1) | ((psbch_payload & 0xFE0000) >> 17));
slot_offset = (((psbch_payload & 0x010000) >> 10) | ((psbch_payload & 0xFC000000) >> 26));
LOG_D(PHY, "PSBCH RX SL-MIB:%x, decoded DFN:slot %d:%d, %x\n",psbch_payload, DFN, slot_offset, *(uint32_t *)decoded_output);
return 0;
}
+374
View File
@@ -0,0 +1,374 @@
/*
* 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
*/
#include "PHY/defs_nr_UE.h"
#include "PHY/LTE_REFSIG/lte_refsig.h"
#include "PHY/NR_REFSIG/nr_mod_table.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h"
#include "PHY/MODULATION/nr_modulation.h"
//#define SL_DEBUG
/**
*This function performs PSBCH SCrambling as described in 38.211.
*Input parameter "output" is scrambled and the scrambled output is stored in this parameter.
*id - SLSS ID used for C_INIT
*length is the length of the buffer.
*/
void sl_psbch_scrambling(uint32_t *output, uint32_t id, uint16_t length)
{
uint32_t x1, x2, s=0;
// x1 is set in lte_gold_generic
x2 = id; // C_INIT
#ifdef SL_DEBUG
printf("SIDELINK: Function %s\n", __func__);
printf("Scrambling params: length %d id %d \n", length, id);
#endif
#ifdef SL_DEBUG
for (int i=0; i<56;i++) {
printf("\nBEFORE SCRAMBLING output[%d]:0x%x\n",i,output[i]);
}
#endif
// get initial 32 scrambing bits
s = lte_gold_generic(&x1, &x2, 1);
#ifdef SL_DEBUG
printf("s: %04x\t", s);
#endif
// scramble in 32bit chunks
int i = 0;
while(i+32 <= length) {
output[i>>5] ^= s;
i += 32;
s = lte_gold_generic(&x1, &x2, 0);
#ifdef SL_DEBUG
printf("s: %04x\t", s);
#endif
}
// scramble remaining bits
for (; i < length; ++i) {
output[i>>5] ^= ((s>>(i&0x1f)&1)<<(i&0x1f));
}
#ifdef SL_DEBUG
for (int i=0; i<56;i++) {
printf("\nAFTER SCRAMBLING output[%d]:0x%x\n",i,output[i]);
}
#endif
}
/**
*This function RE MAPS PSS, SSS sequences as described in 38.211.
*txF is the data in frequency domain, sync_seq = PSS or SSS seq
*startsym = 1 for PSS, 3 for SSS
*re_offset = sample which points to first RE + SSB start RE
*scaling factor = scaling factor used for PSS, SSS (determined according to PSBCH pwr)
*symbol size = OFDM symbol size used for RE Mapping
*/
void sl_map_pss_or_sss(c16_t *txF, int16_t *sync_seq, uint16_t startsym,
uint16_t re_offset, uint16_t scaling_factor,
uint16_t symbol_size)
{
#ifdef SL_DEBUG
printf("%s. DEBUG PSBCH TX: RE MAPPING of PSS/SSS \n", __func__);
printf("Input Params - StartSYM:%d, NUMSYM:%d, RE_OFFSET:%d, num_REs:%d, scaling_factor:%d, symbol_size:%d\n",
startsym, SL_NR_NUM_PSS_OR_SSS_SYMBOLS,re_offset, SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL, scaling_factor, symbol_size);
#endif
// RE Mapping of SL-PSS, SL-SSS
for (int l = startsym;l < (startsym + SL_NR_NUM_PSS_OR_SSS_SYMBOLS);l++) {
int k = re_offset % symbol_size;
int index = 0, offset = 0;
for (int m = 0;m < SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL;m++) {
offset = l*symbol_size + k;
if ((m < 2) || (m >= (SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL - 3))) {
txF[offset].r = 0; //Set REs 0,1,129,130,131 = 0
#ifdef SL_DEBUG
printf("sym:%d, RE:%d, txF[%d]:%d.%d \n", l, m, offset, txF[offset].r,txF[offset].i);
#endif
} else {
txF[offset].r = (sync_seq[index] * scaling_factor) >> 15;
#ifdef SL_DEBUG
printf("sym:%d, RE:%d, txF[%d]:%d.%d, syncseq[%d]:%d \n", l, m, offset, txF[offset].r,txF[offset].i, index, sync_seq[index]);
#endif
index++;
}
txF[offset].i = 0;
k = (k + 1) % symbol_size;
}
}
}
/**
* This function Generates the PSBCH DATA Modulation symbols and RE MAPS PSBCH Modulated symbols
* and PSBCH DMRS sequences as described in 38.211.
* txF is the data in frequency domain
* payload is the PSBCH payload (SL-MIB given by higher layers)
* id - SLSS ID used for knowing which DMRS sequence to be used.
* Cp - NORMAL of extended Cyclic prefix
* startsym = 0 and then PSBCH is mapped from symbols 5-13 if normal , 5-11 if extended
* re_offset = sample which points to first RE + SSB start RE
* scaling factor = scaling factor used for PSS, SSS (determined according to PSBCH pwr)
* symbol size = OFDM symbol size used for RE Mapping
*/
void sl_generate_and_map_psbch(c16_t *txF, uint32_t *payload, uint16_t id,
uint16_t cp, uint16_t re_offset,
uint16_t scaling_factor, uint16_t symbol_size,
c16_t *psbch_dmrs)
{
uint64_t psbch_a_reversed = 0;
uint16_t num_psbch_modsym = 0, numsym = 0;
const int mod_order = 2;//QPSK
uint32_t encoder_output[SL_NR_POLAR_PSBCH_E_DWORD];
struct complex16 psbch_modsym[SL_NR_NUM_PSBCH_MODULATED_SYMBOLS];
LOG_D(PHY, "PSBCH TX: Generation accg to 38.212, 38.211. SLSS id:%d\n", id);
// Encoder reversal
for (int i=0; i<SL_NR_POLAR_PSBCH_PAYLOAD_BITS; i++)
psbch_a_reversed |= (((uint64_t)*payload>>i)&1)<<(31-i);
#ifdef SL_DEBUG
printf("DEBUG PSBCH TX: 38.212 PSBCH CRC + Channel coding (POLAR) + Rate Matching:\n");
printf("PSBCH payload:%x, Reversed Payload:%016lx\n",*payload, psbch_a_reversed);
#endif
/// CRC, coding and rate matching
polar_encoder_fast(&psbch_a_reversed, (void*)encoder_output, 0, 0,
SL_NR_POLAR_PSBCH_MESSAGE_TYPE,
SL_NR_POLAR_PSBCH_PAYLOAD_BITS,
SL_NR_POLAR_PSBCH_AGGREGATION_LEVEL);
#ifdef SL_DEBUG
for (int i=0; i<SL_NR_POLAR_PSBCH_E_DWORD; i++)
printf("encoderoutput[%d]: 0x%08x\t", i, encoder_output[i]);
printf("\n");
#endif
/// 38.211 Scrambling
if (cp) { // EXT Cyclic prefix
sl_psbch_scrambling(encoder_output, id, SL_NR_POLAR_PSBCH_E_EXT_CP); //for Extended Cyclic prefix
num_psbch_modsym = SL_NR_POLAR_PSBCH_E_EXT_CP/mod_order;
numsym = SL_NR_NUM_SYMBOLS_SSB_EXT_CP;
AssertFatal(1==0, "EXT CP is not yet supported\n");
}
else { // Normal CP
sl_psbch_scrambling(encoder_output, id, SL_NR_POLAR_PSBCH_E_NORMAL_CP); //for Cyclic prefix
num_psbch_modsym = SL_NR_POLAR_PSBCH_E_NORMAL_CP/mod_order;
numsym = SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
}
LOG_D(PHY,"PSBCH TX: 38.211 Scrambling done. Number of bits:%d \n",
SL_NR_POLAR_PSBCH_E_NORMAL_CP);
#ifdef SL_DEBUG
printf("38211 STEP: PSBCH Scrambling \n");
for (int i=0; i<SL_NR_POLAR_PSBCH_E_NORMAL_CP/32; i++)
printf("Scrambleroutput[%d]: 0x%08x\t", i, encoder_output[i]);
printf("\n");
#endif
#ifdef SL_DEBUG
printf("SIDELINK PSBCH TX: 38211 STEP: QPSK Modulation of PSBCH symbols:%d, symbols in PSBCH:%d\n", num_psbch_modsym, numsym);
#endif
/// 38.211 QPSK modulation
nr_modulation(encoder_output, num_psbch_modsym*mod_order,mod_order,(int16_t *)psbch_modsym);
// RE MApping of PSBCH and PSBCH DMRS
int index = 0, dmrs_index = 0;
const int numre=SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL;
#ifdef SL_DEBUG
LOG_M("sl_psbch_data_symbols.m", "psbch_sym", (void*)psbch_modsym, num_psbch_modsym, 1, 1);
LOG_M("sl_psbch_dmrs_symbols.m", "psbch_dmrs", (void*)psbch_dmrs, SL_NR_NUM_PSBCH_DMRS_RE, 1, 1);
#endif
#ifdef SL_DEBUG
printf("\nMapping Sidelink PSBCH DMRS, PSBCH modulation symbols to 132 REs\n");
#endif
#ifdef SL_DEBUG
printf("%s. DEBUG PSBCH TX: RE MAPPING of PSBCH DATA AND DMRS \n", __func__);
printf("Input Params - StartSYM:%d, NUMSYM:%d, RE_OFFSET:%d, num_REs:%d, scaling_factor:%d, symbol_size:%d\n",
0, numsym,re_offset, numre, scaling_factor, symbol_size);
#endif
for (int l=0;l < numsym;) {
int k = re_offset % symbol_size;
int symbol_offset = l*symbol_size;
int offset = 0;
for (int m=0; m < numre;m++) {
// Maps PSBCH DMRS in every 4th RE ex:0,4,....128
// Maps PSBCH in all other REs ex: 1,2,3,5,6,...127,129,130,131
offset = symbol_offset + k;
#ifdef SL_DEBUG
printf("symbol:%d, symbol_offset:%d, k:%d, re:%d, sampleoffset:%d ", l, symbol_offset, k, m, offset);
#endif
if (m % 4 == 0) {
txF[offset] = c16xmulConstShift(psbch_dmrs[dmrs_index], scaling_factor, 15);
#ifdef SL_DEBUG
printf("txF[%d]:%d,%d, psbch_dmrs[%d]:%d,%d ", offset, txF[offset].r,
txF[offset].i, dmrs_index, psbch_dmrs[dmrs_index].r, psbch_dmrs[dmrs_index].i);
#endif
dmrs_index++;
} else {
txF[offset] = c16xmulConstShift(psbch_modsym[index], scaling_factor, 15);
#ifdef SL_DEBUG
printf("txF[%d]:%d,%d, psbch_modsym[%d]:%d,%d\n", offset, txF[offset].r,
txF[offset].i, index ,psbch_modsym[index].r, psbch_modsym[index].i);
#endif
index++;
}
k = (k + 1) % symbol_size;
}
LOG_D(PHY, "PSBCH TX: 38211 STEP: RE MAPPING OF PSBCH, PSBCH DMRS DONE. symbol:%d, first RE offset:%d, Last RE offset:%d, Num PSBCH DATA REs:%d, Num PSBCH DMRS REs:%d\n",
l, symbol_offset+re_offset, offset, index, dmrs_index);
l = (l == 0) ? 5: l+1;
}
}
/**
*This function prepares the PSBCH block and RE MAPS PSS, SSS, PSBCH DATA, PSBCH DMRS into buffer txF.
*Called by the L1 Scheduler when MAC triggers PHY to send PSBCH
*UE is the UE context.
*frame, slot points to the TTI in which PSBCH TX will be transmitted
*/
void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx,
uint32_t slot_tx,
sl_nr_tx_config_psbch_pdu_t *psbch_vars,
c16_t **txdataF)
{
sl_nr_ue_phy_params_t *sl_ue_phy_params = &UE->SL_UE_PHY_PARAMS;
uint16_t slss_id = psbch_vars->tx_slss_id;
NR_DL_FRAME_PARMS *sl_fp = &sl_ue_phy_params->sl_frame_params;
uint32_t psbch_payload = *((uint32_t *)psbch_vars->psbch_payload);
LOG_D(PHY,"PSBCH TX: slss-id %d, psbch payload %x \n", slss_id, psbch_payload);
// Insert FN and Slot number into SL-MIB
uint32_t mask = ~(0x700 | 0xFE0000 | 0x10000 | 0xFC000000);
psbch_payload &= mask;
psbch_payload |= ((frame_tx%1024)<<1) & 0x700;
psbch_payload |= ((frame_tx%1024)<<17) & 0xFE0000;
psbch_payload |= (slot_tx<<10) & 0x10000;
psbch_payload |= (slot_tx<<26) & 0xFC000000;
#ifdef SL_DEBUG
printf("DEBUG PSBCH TX: DFN, SLOT included. psbch_a :0x%08x, frame:%d, slot:%d\n",
psbch_payload, frame_tx, slot_tx);
#endif
LOG_D(PHY,"PSBCH TX: Frame.Slot %d.%d. Payload::0x%08x, slssid:%d\n",
frame_tx, slot_tx, psbch_payload, slss_id);
// GENERATE Sidelink PSS,SSS Sequences, PSBCH DMRS Symbols, PSBCH Symbols
int16_t *sl_pss = &sl_ue_phy_params->init_params.sl_pss[slss_id/336][0];
int16_t *sl_sss = &sl_ue_phy_params->init_params.sl_sss[slss_id][0];
uint16_t re_offset = sl_fp->first_carrier_offset + sl_fp->ssb_start_subcarrier;
uint16_t symbol_size = sl_fp->ofdm_symbol_size;
// TBD: Need to be replaced by function which calculates scaling factor based on psbch tx power
uint16_t scaling_factor = AMP;
struct complex16 *txF = &txdataF[0][0];
uint16_t startsym = SL_NR_PSS_START_SYMBOL;
#ifdef SL_DEBUG
printf("DEBUG PSBCH TX: MAP PSS. startsym:%d, PSS RE START:%d, scaling factor:%d\n",
startsym, re_offset, scaling_factor);
#endif
sl_map_pss_or_sss(txF, sl_pss, startsym, re_offset, scaling_factor, symbol_size); // PSS
startsym += SL_NR_NUM_PSS_SYMBOLS;
#ifdef SL_DEBUG
printf("DEBUG PSBCH TX: MAP SSS. startsym:%d, SSS RE START:%d, scaling factor:%d\n",
startsym, re_offset, scaling_factor);
#endif
sl_map_pss_or_sss(txF, sl_sss, startsym, re_offset, scaling_factor, symbol_size); // SSS
#ifdef SL_DEBUG
printf("DEBUG PSBCH TX: MAP PSBCH DATA AND DMRS. cyclicPrefix:%d, PSS RE START:%d, scaling factor:%d\n",
sl_fp->Ncp, re_offset, scaling_factor);
#endif
struct complex16 *psbch_dmrs = &sl_ue_phy_params->init_params.psbch_dmrs_modsym[slss_id][0];
sl_generate_and_map_psbch(txF, &psbch_payload, slss_id,
sl_fp->Ncp, re_offset, scaling_factor, symbol_size,
psbch_dmrs);
#ifdef SL_DEBUG
printf("DEBUG PSBCH TX: txdataF Prepared\n");
#endif
#ifdef SL_DEBUG
LOG_M("sl_psbch_block.m", "sl_txF", (void*)txdataF[0], symbol_size*14, 1, 1);
#endif
}
@@ -418,6 +418,42 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
void dump_nrdlsch(PHY_VARS_NR_UE *ue,uint8_t gNB_id,uint8_t nr_slot_rx,unsigned int *coded_bits_per_codeword,int round, unsigned char harq_pid);
void nr_a_sum_b(c16_t *input_x, c16_t *input_y, unsigned short nb_rb);
int nr_rx_psbch(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
NR_DL_FRAME_PARMS *frame_parms,
uint8_t *decoded_output,
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
uint16_t slss_id);
void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx, uint32_t slot_tx,
sl_nr_tx_config_psbch_pdu_t *psbch_vars,
c16_t **txdataF);
nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, int num_frames);
//Reuse already existing PBCH functions
int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
NR_DL_FRAME_PARMS *frame_parms,
int nb_re);
void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
int nb_re,
struct complex16 rxdataF_comp[][PBCH_MAX_RE_PER_SYMBOL],
NR_DL_FRAME_PARMS *frame_parms,
uint8_t output_shift);
void nr_pbch_unscrambling(int16_t *demod_pbch_e,
uint16_t Nid,
uint8_t nushift,
uint16_t M,
uint16_t length,
uint8_t bitwise,
uint32_t unscrambling_mask,
uint32_t pbch_a_prime,
uint32_t *pbch_a_interleaved);
void nr_pbch_quantize(int16_t *pbch_llr8, int16_t *pbch_llr, uint16_t len);
/**@}*/
#endif
+100
View File
@@ -704,3 +704,103 @@ static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, i
return peak_position;
}
void sl_generate_pss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint8_t n_sl_id2, uint16_t scaling)
{
int i = 0, m = 0;
int16_t x[SL_NR_PSS_SEQUENCE_LENGTH];
const int x_initial[7] = {0, 1, 1 , 0, 1, 1, 1};
int16_t *sl_pss = sl_init_params->sl_pss[n_sl_id2];
int16_t *sl_pss_for_sync = sl_init_params->sl_pss_for_sync[n_sl_id2];
LOG_D(PHY, "SIDELINK PSBCH INIT: PSS Generation with N_SL_id2:%d\n", n_sl_id2);
#ifdef SL_DEBUG_INIT
printf("SIDELINK: PSS Generation with N_SL_id2:%d\n", n_sl_id2);
#endif
/// Sequence generation
for (i=0; i < 7; i++)
x[i] = x_initial[i];
for (i=0; i < (SL_NR_PSS_SEQUENCE_LENGTH - 7); i++) {
x[i+7] = (x[i + 4] + x[i]) %2;
}
for (i=0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
m = (i + 22 + 43*n_sl_id2) % SL_NR_PSS_SEQUENCE_LENGTH;
sl_pss_for_sync[i] = (1 - 2*x[m]);
sl_pss[i] = sl_pss_for_sync[i] * scaling;
#ifdef SL_DEBUG_INIT_DATA
printf("m:%d, sl_pss[%d]:%d\n", m, i, sl_pss[i]);
#endif
}
#ifdef SL_DUMP_INIT_SAMPLES
LOG_M("sl_pss_seq.m", "sl_pss", (void*)sl_pss, SL_NR_PSS_SEQUENCE_LENGTH, 1, 0);
#endif
}
// This cannot be done at init time as ofdm symbol size, ssb start subcarrier depends on configuration
// done at SLSS read time.
void sl_generate_pss_ifft_samples(sl_nr_ue_phy_params_t *sl_ue_params, SL_NR_UE_INIT_PARAMS_t *sl_init_params)
{
uint8_t id2 = 0;
int16_t *sl_pss = NULL;
NR_DL_FRAME_PARMS *sl_fp = &sl_ue_params->sl_frame_params;
int16_t scaling_factor = AMP;
int32_t *pss_T = NULL;
uint16_t k = 0;
c16_t pss_F[sl_fp->ofdm_symbol_size]; // IQ samples in freq domain
LOG_I(PHY, "SIDELINK INIT: Generation of PSS time domain samples. scaling_factor:%d\n", scaling_factor);
for (id2 = 0; id2 < SL_NR_NUM_IDs_IN_PSS; id2++) {
k = sl_fp->first_carrier_offset + sl_fp->ssb_start_subcarrier + 2; // PSS in from REs 2-129
if (k >= sl_fp->ofdm_symbol_size) k -= sl_fp->ofdm_symbol_size;
pss_T = &sl_init_params->sl_pss_for_correlation[id2][0];
sl_pss = sl_init_params->sl_pss[id2];
memset(pss_T, 0, sl_fp->ofdm_symbol_size * sizeof(pss_T[0]));
memset(pss_F, 0, sl_fp->ofdm_symbol_size * sizeof(c16_t));
for (int i=0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
pss_F[k].r = (sl_pss[i] * scaling_factor) >> 15;
//pss_F[2*k] = (sl_pss[i]/23170) * 4192;
//pss_F[2*k+1] = 0;
#ifdef SL_DEBUG_INIT_DATA
printf("id:%d, k:%d, pss_F[%d]:%d, sl_pss[%d]:%d\n", id2, k, 2*k, pss_F[2*k], i, sl_pss[i]);
#endif
k++;
if (k == sl_fp->ofdm_symbol_size) k=0;
}
idft((int16_t)get_idft(sl_fp->ofdm_symbol_size),
(int16_t *)&pss_F[0], /* complex input */
(int16_t *)&pss_T[0], /* complex output */
1); /* scaling factor */
}
#ifdef SL_DUMP_PSBCH_TX_SAMPLES
LOG_M("sl_pss_TD_id0.m", "pss_TD_0", (void*)sl_init_params->sl_pss_for_correlation[0], sl_fp->ofdm_symbol_size, 1, 1);
LOG_M("sl_pss_TD_id1.m", "pss_TD_1", (void*)sl_init_params->sl_pss_for_correlation[1], sl_fp->ofdm_symbol_size, 1, 1);
#endif
}
+52 -8
View File
@@ -63,13 +63,6 @@
#define INITIAL_SSS_NR (7)
static const int16_t phase_re_nr[PHASE_HYPOTHESIS_NUMBER]
// -pi/3 ---- pi/3
= {16384, 20173, 23571, 26509, 28932, 30791, 32051, 32687, 32687, 32051, 30791, 28932, 26509, 23571, 20173, 16384};
static const int16_t phase_im_nr[PHASE_HYPOTHESIS_NUMBER] // -pi/3 ---- pi/3
= {-28377, -25821, -22762, -19260, -15383, -11207, -6813, -2286, 2286, 6813, 11207, 15383, 19260, 22762, 25821, 28377};
static int16_t d_sss[N_ID_2_NUMBER][N_ID_1_NUMBER][LENGTH_SSS_NR];
void init_context_sss_nr(int amp)
@@ -475,7 +468,7 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
// This is the inner product using one particular value of each unknown parameter
for (i=0; i < LENGTH_SSS_NR; i++) {
metric_re += d[i] * ((phase_re_nr[phase] * sss[i].r - phase_im_nr[phase] * sss[i].i) >> SCALING_METRIC_SSS_NR);
metric_re += d[i] * ((phase_nr[phase].r * sss[i].r - phase_nr[phase].i * sss[i].i) >> SCALING_METRIC_SSS_NR);
}
metric = metric_re;
@@ -537,3 +530,54 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
return true;
}
void sl_generate_sss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint16_t slss_id, uint16_t scaling)
{
int i = 0;
int m0, m1;
int n_sl_id1, n_sl_id2;
int16_t *sl_sss = sl_init_params->sl_sss[slss_id];
int16_t *sl_sss_for_sync = sl_init_params->sl_sss_for_sync[slss_id];
int16_t x0[SL_NR_SSS_SEQUENCE_LENGTH], x1[SL_NR_SSS_SEQUENCE_LENGTH];
const int x_initial[7] = { 1, 0, 0, 0, 0, 0, 0 };
n_sl_id1 = slss_id % 336;
n_sl_id2 = slss_id / 336;
LOG_D(PHY, "SIDELINK INIT: SSS Generation with N_SL_id1:%d N_SL_id2:%d\n", n_sl_id1, n_sl_id2);
#ifdef SL_DEBUG_INIT
printf("SIDELINK: SSS Generation with slss_id:%d, N_SL_id1:%d, N_SL_id2:%d\n", slss_id, n_sl_id1, n_sl_id2);
#endif
for ( i=0 ; i < 7 ; i++) {
x0[i] = x_initial[i];
x1[i] = x_initial[i];
}
for ( i=0 ; i < SL_NR_SSS_SEQUENCE_LENGTH - 7 ; i++) {
x0[i+7] = (x0[i + 4] + x0[i]) % 2;
x1[i+7] = (x1[i + 1] + x1[i]) % 2;
}
m0 = 15*(n_sl_id1/112) + (5*n_sl_id2);
m1 = n_sl_id1 % 112;
for (i = 0; i < SL_NR_SSS_SEQUENCE_LENGTH ; i++) {
sl_sss_for_sync[i] = (1 - 2*x0[(i + m0) % SL_NR_SSS_SEQUENCE_LENGTH] ) * (1 - 2*x1[(i + m1) % SL_NR_SSS_SEQUENCE_LENGTH] );
sl_sss[i] = sl_sss_for_sync[i] * scaling;
#ifdef SL_DEBUG_INIT_DATA
printf("m0:%d, m1:%d, sl_sss_for_sync[%d]:%d, sl_sss[%d]:%d\n", m0, m1, i, sl_sss_for_sync[i], i, sl_sss[i]);
#endif
}
#ifdef SL_DUMP_PSBCH_TX_SAMPLES
LOG_M("sl_sss_seq.m", "sl_sss", (void*)sl_sss, SL_NR_SSS_SEQUENCE_LENGTH, 1, 0);
LOG_M("sl_sss_forsync_seq.m", "sl_sss_for_sync", (void*)sl_sss_for_sync, SL_NR_SSS_SEQUENCE_LENGTH, 1, 0);
#endif
}
+7
View File
@@ -242,6 +242,13 @@ extern "C" {
};
}
__attribute__((always_inline)) inline c16_t c16xmulConstShift(const c16_t a, const int b, const int Shift) {
return (c16_t) {
.r = (int16_t)((a.r * b) >> Shift),
.i = (int16_t)((a.i * b) >> Shift)
};
}
__attribute__((always_inline)) inline c32_t c32x16maddShift(const c16_t a, const c16_t b, const c32_t c, const int Shift) {
return (c32_t) {
.r = ((a.r * b.r - a.i * b.i) >> Shift) + c.r,
+14
View File
@@ -39,6 +39,7 @@
#include "defs_nr_common.h"
#include "CODING/nrPolar_tools/nr_polar_pbch_defs.h"
#include "PHY/defs_nr_sl_UE.h"
#include <stdio.h>
#include <stdlib.h>
@@ -591,6 +592,10 @@ typedef struct PHY_VARS_NR_UE_s {
uint8_t *phy_sim_dlsch_b;
notifiedFIFO_t tx_resume_ind_fifo[NR_MAX_SLOTS_PER_FRAME];
//Sidelink parameters
sl_nr_sidelink_mode_t sl_mode;
sl_nr_ue_phy_params_t SL_UE_PHY_PARAMS;
} PHY_VARS_NR_UE;
typedef struct {
@@ -612,11 +617,20 @@ typedef struct {
typedef struct nr_phy_data_tx_s {
NR_UE_ULSCH_t ulsch;
NR_UE_PUCCH pucch_vars;
//Sidelink Rx action decided by MAC
sl_nr_tx_config_type_enum_t sl_tx_action;
sl_nr_tx_config_psbch_pdu_t psbch_vars;
} nr_phy_data_tx_t;
typedef struct nr_phy_data_s {
NR_UE_PDCCH_CONFIG phy_pdcch_config;
NR_UE_DLSCH_t dlsch[2];
//Sidelink Rx action decided by MAC
sl_nr_rx_config_type_enum_t sl_rx_action;
} nr_phy_data_t;
/* this structure is used to pass both UE phy vars and
* proc to the function UE_thread_rxn_txnp4
+2 -2
View File
@@ -96,6 +96,8 @@
#define MAX_DELAY_COMP 20
#define PBCH_MAX_RE_PER_SYMBOL (20*12)
typedef enum {
NR_MU_0=0,
NR_MU_1,
@@ -168,8 +170,6 @@ struct NR_DL_FRAME_PARMS {
/// Frame type (0 FDD, 1 TDD)
frame_type_t frame_type;
uint8_t tdd_config;
/// Sidelink Cell ID
uint16_t Nid_SL;
/// Cell ID
uint16_t Nid_cell;
/// subcarrier spacing (15,30,60,120)
+166
View File
@@ -0,0 +1,166 @@
/*
* 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/defs_nr_sl_UE.h
\brief Top-level defines and structure definitions
\author
\date
\version
\company Fraunhofer
\email:
\note
\warning
*/
#ifndef _DEFS_NR_SL_UE_H_
#define _DEFS_NR_SL_UE_H_
#include "PHY/types.h"
#include "PHY/defs_nr_common.h"
#include "nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h"
#include "common/utils/time_meas.h"
// (33*(13-4))
// Normal CP - NUM_SSB_Symbols = 13. 4 symbols for PSS, SSS
#define SL_NR_NUM_PSBCH_DMRS_RE 297
//ceil(2(QPSK)*SL_NR_NUM_PSBCH_DMRS_RE/32)
#define SL_NR_NUM_PSBCH_DMRS_RE_DWORD 20
//11 RBs for PSBCH in one symbol * 12 REs
#define SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL 132
//3 DMRS REs per RB * 11 RBS in one symbol
#define SL_NR_NUM_PSBCH_DMRS_RE_IN_ONE_SYMBOL 33
//9 PSBCH DATA REs * 11 RBS in one symbol
#define SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL 99
#define SL_NR_NUM_PSBCH_RBS_IN_ONE_SYMBOL 11
// SL_NR_POLAR_PSBCH_E_NORMAL_CP/2 bits because QPSK used for PSBCH.
// 11 * (12-3 DMRS REs) * 9 symbols for PSBCH
#define SL_NR_NUM_PSBCH_MODULATED_SYMBOLS 891
#define SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_RB 9
#define SL_NR_NUM_PSBCH_DMRS_RE_IN_ONE_RB 3
// 11 * (12-3 DMRS REs) * 9 symbols for PSBCH
#define SL_NR_NUM_PSBCH_DATA_RE_IN_ALL_SYMBOLS 891
#define SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP 13
#define SL_NR_NUM_SYMBOLS_SSB_EXT_CP 11
#define SL_NR_NUM_PSS_SYMBOLS 2
#define SL_NR_NUM_SSS_SYMBOLS 2
#define SL_NR_PSS_START_SYMBOL 1
#define SL_NR_SSS_START_SYMBOL 3
#define SL_NR_NUM_PSS_OR_SSS_SYMBOLS 2
#define SL_NR_PSS_SEQUENCE_LENGTH 127
#define SL_NR_SSS_SEQUENCE_LENGTH 127
#define SL_NR_NUM_IDs_IN_PSS 2
#define SL_NR_NUM_IDs_IN_SSS 336
#define SL_NR_NUM_SLSS_IDs 672
typedef enum sl_nr_sidelink_mode {
SL_NOT_SUPPORTED = 0,
SL_MODE1_SUPPORTED,
SL_MODE2_SUPPORTED
} sl_nr_sidelink_mode_t;
//(11*(12-3 DMRS REs) * 2 (QPSK used)
#define SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL 198
typedef struct SL_NR_UE_INIT_PARAMS {
//gold sequences for PSBCH DMRS
uint32_t psbch_dmrs_gold_sequences[SL_NR_NUM_SLSS_IDs][SL_NR_NUM_PSBCH_DMRS_RE_DWORD]; // Gold sequences for PSBCH DMRS
//PSBCH DMRS QPSK modulated symbols for all possible SLSS Ids
struct complex16 psbch_dmrs_modsym[SL_NR_NUM_SLSS_IDs][SL_NR_NUM_PSBCH_DMRS_RE];
// Scaled values
int16_t sl_pss[SL_NR_NUM_IDs_IN_PSS][SL_NR_PSS_SEQUENCE_LENGTH];
int16_t sl_sss[SL_NR_NUM_SLSS_IDs][SL_NR_SSS_SEQUENCE_LENGTH];
// Contains Not scaled values just the simple generated sequence
int16_t sl_pss_for_sync[SL_NR_NUM_IDs_IN_PSS][SL_NR_PSS_SEQUENCE_LENGTH];
int16_t sl_sss_for_sync[SL_NR_NUM_SLSS_IDs][SL_NR_SSS_SEQUENCE_LENGTH];
int32_t **sl_pss_for_correlation; // IFFT samples for correlation
} SL_NR_UE_INIT_PARAMS_t;
typedef struct SL_NR_SYNC_PARAMS {
// Indicating start of SSB block in the initial set of samples
uint32_t ssb_offset;
// Freq Offset calculated
int32_t freq_offset;
uint32_t remaining_frames;
uint32_t rx_offset;
uint32_t slot_offset;
uint16_t N_sl_id2; //id2 determined from PSS during sync ref UE selection
uint16_t N_sl_id1; //id2 determined from SSS during sync ref UE selection
uint16_t N_sl_id; //ID calculated from ID1 and ID2
int32_t psbch_rsrp; //rsrp of the decoded psbch during sync ref ue selection
uint32_t DFN; // DFN calculated after sync ref UE search
} SL_NR_SYNC_PARAMS_t;
typedef struct SL_NR_UE_PSBCH {
// AVG POWER OF PSBCH DMRS in dB/RE
int16_t rsrp_dB_per_RE;
// AVG POWER OF PSBCH DMRS in dBm/RE
int16_t rsrp_dBm_per_RE;
// STATS - CRC Errors observed during PSBCH reception
uint16_t rx_errors;
// STATS - Receptions with CRC OK
uint16_t rx_ok;
// STATS - transmissions of PSBCH by the UE
uint16_t num_psbch_tx;
} SL_NR_UE_PSBCH_t;
typedef struct sl_nr_ue_phy_params {
SL_NR_UE_INIT_PARAMS_t init_params;
SL_NR_SYNC_PARAMS_t sync_params;
// Sidelink PHY PARAMETERS USED FOR PSBCH reception/Txn
SL_NR_UE_PSBCH_t psbch;
//Configuration parameters from MAC
sl_nr_phy_config_request_t sl_config;
NR_DL_FRAME_PARMS sl_frame_params;
time_stats_t phy_proc_sl_tx;
time_stats_t phy_proc_sl_rx;
time_stats_t channel_estimation_stats;
time_stats_t ue_sl_indication_stats;
} sl_nr_ue_phy_params_t;
#endif