Commit 951318c4 authored by Raghavendra Dinavahi's avatar Raghavendra Dinavahi

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
parent 3f3a9869
......@@ -718,6 +718,7 @@ target_link_libraries(SCHED_UE_LIB PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
set(SCHED_SRC_NR_UE
${OPENAIR1_DIR}/SCHED_NR_UE/phy_procedures_nr_ue.c
${OPENAIR1_DIR}/SCHED_NR_UE/phy_procedures_nr_ue_sl.c
${OPENAIR1_DIR}/SCHED_NR_UE/fapi_nr_ue_l1.c
${OPENAIR1_DIR}/SCHED_NR_UE/phy_frame_config_nr_ue.c
${OPENAIR1_DIR}/SCHED_NR_UE/harq_nr.c
......@@ -1086,8 +1087,11 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/sss_nr.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
......@@ -2244,6 +2248,22 @@ target_link_libraries(nr_pbchsim PRIVATE
)
target_link_libraries(nr_pbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
add_executable(nr_psbchsim
${OPENAIR1_DIR}/SIMULATION/NR_PHY/psbchsim.c
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
${OPENAIR_DIR}/common/utils/nr/nr_common.c
${OPENAIR_DIR}/executables/softmodem-common.c
${OPENAIR2_DIR}/RRC/NAS/nas_config.c
${NR_UE_RRC_DIR}/rrc_nsa.c
${NFAPI_USER_DIR}/nfapi.c
${NFAPI_USER_DIR}/gnb_ind_vars.c
${PHY_INTERFACE_DIR}/queue_t.c
)
target_link_libraries(nr_psbchsim PRIVATE
-Wl,--start-group UTIL SIMU SIMU_ETH PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -lz -Wl,--end-group
m pthread ${T_LIB} ITTI dl shlib_loader
)
target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
#PUCCH ---> Prashanth
add_executable(nr_pucchsim
......
......@@ -511,4 +511,16 @@
<search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
<nruns>3</nruns>
</testCase>
<testCase id="NR-Sidelink">
<desc>NR-Sidelink Test cases. (Test1: SLSS Search),
(Test2: PSBCH TxRx)</desc>
<main_exec>nr_psbchsim</main_exec>
<main_exec_args>-I
-n 10</main_exec_args>
<tags>test1 test2</tags>
<search_expr_true>PSBCH test OK</search_expr_true>
<search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
<nruns>3</nruns>
</testCase>
</testCaseList>
......@@ -320,7 +320,7 @@ function main() {
-P | --phy_simulators)
SIMUS_PHY=1
# TODO: fix: dlsim_tm4 pucchsim prachsim pdcchsim pbchsim mbmssim
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim"
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim"
echo_info "Will compile dlsim, ulsim, ..."
shift;;
-s | --check)
......
/*
* 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
......@@ -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);
}
......
......@@ -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,15 @@ 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 +497,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 +712,35 @@ 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);
}
\ No newline at end of file
......@@ -428,7 +428,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);
}
......@@ -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
......@@ -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,
......
......@@ -34,12 +34,107 @@
#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;
rx_offset += ue->rx_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 +193,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,
......
......@@ -197,10 +197,17 @@ int nr_pdcch_dmrs_rx(PHY_VARS_NR_UE *ue,
int nr_pbch_dmrs_rx(int symbol,
unsigned int *nr_gold_pbch,
int32_t *output)
int32_t *output,
bool sidelink)
{
int m,m0,m1;
uint8_t idx=0;
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;
......@@ -214,6 +221,7 @@ int nr_pbch_dmrs_rx(int symbol,
m0=84;
m1=144;
}
}
// printf("Generating pilots symbol %d, m0 %d, m1 %d\n",symbol,m0,m1);
/// QPSK modulation
for (m=m0; m<m1; m++) {
......
......@@ -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)
{
......@@ -154,3 +155,65 @@ 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];
#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 = nr_qpsk_mod_table[2*idx];
modulated_dmrs_sym[m].i = nr_qpsk_mod_table[(2*idx) + 1];
#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, nr_qpsk_mod_table[2*idx], nr_qpsk_mod_table[(2*idx) + 1]);
#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
}
......@@ -33,7 +33,8 @@
*/
int nr_pbch_dmrs_rx(int dmrss,
unsigned int *nr_gold_pbch,
int32_t *output);
int32_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
......@@ -69,5 +70,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
......@@ -658,7 +658,7 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
#endif
// generate pilot
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0]);
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0],0);
for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
......@@ -779,15 +779,18 @@ int nr_pbch_dmrs_correlation(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;
int pilot[200] __attribute__((aligned(16)));
......@@ -798,24 +801,49 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
int ch_offset,symbol_offset;
//int slot_pbch;
uint8_t nushift;
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;
ch_offset = ue->frame_parms.ofdm_symbol_size*symbol;
uint32_t *gold_seq = NULL;
if (sidelink) {
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);
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;
ch_offset = fp->ofdm_symbol_size*symbol;
symbol_offset = fp->ofdm_symbol_size*symbol;
k = nushift;
#ifdef DEBUG_PBCH
printf("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);
printf("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, fp->ofdm_symbol_size, fp->Ncp, Ns, k, symbol);
#endif
switch (k) {
......@@ -851,7 +879,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;
......@@ -898,20 +926,20 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
}
// generate pilot
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0]);
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;
pil = (int16_t *)&pilot[0];
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
dl_ch = (int16_t *)&dl_ch_estimates[aarx][ch_offset];
memset(dl_ch,0,sizeof(struct complex16)*(ue->frame_parms.ofdm_symbol_size));
memset(dl_ch,0,sizeof(struct complex16)*(fp->ofdm_symbol_size));
#ifdef DEBUG_PBCH
printf("pbch ch est pilot addr %p RB_DL %d\n",&pilot[0], ue->frame_parms.N_RB_DL);
printf("k %d, first_carrier %d\n",k,ue->frame_parms.first_carrier_offset);
printf("pbch ch est pilot addr %p RB_DL %d\n",&pilot[0], fp->N_RB_DL);
printf("k %d, first_carrier %d\n",k,fp->first_carrier_offset);
printf("rxF addr %p\n", rxF);
printf("dl_ch addr %p\n",dl_ch);
#endif
......@@ -930,7 +958,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
dl_ch,
16);
pil += 2;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
//for (int i= 0; i<8; i++)
......@@ -948,7 +976,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
dl_ch,
16);
pil += 2;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
......@@ -963,11 +991,11 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
dl_ch,
16);
pil += 2;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
dl_ch += 24;
for (pilot_cnt=3; pilot_cnt<(3*20); pilot_cnt += 3) {
for (pilot_cnt=3; pilot_cnt<(3*num_rbs); pilot_cnt += 3) {
// if (pilot_cnt == 30)
// rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k)];
......@@ -975,7 +1003,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
// 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;
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
dl_ch += 288;
}
......@@ -994,7 +1022,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
// printf("pilot_cnt %d dl_ch %d %d\n", pilot_cnt, dl_ch+i, *(dl_ch+i));
pil += 2;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
......@@ -1009,7 +1037,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
dl_ch,
16);
pil += 2;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
......@@ -1024,13 +1052,13 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
dl_ch,
16);
pil += 2;
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
dl_ch += 24;
}
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);
......@@ -1041,13 +1069,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);
......
......@@ -65,15 +65,18 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
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,56 @@ 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 += rxF[offset].r*rxF[offset].r + rxF[offset].i*rxF[offset].i;
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);
}
\ No newline at end of file
......@@ -153,8 +153,8 @@ int nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size];
for(int i=pbch_initial_symbol; i<pbch_initial_symbol+3;i++)
nr_pbch_channel_estimation(ue,estimateSz, dl_ch_estimates, dl_ch_estimates_time,
proc,i,i-pbch_initial_symbol,temp_ptr->i_ssb,temp_ptr->n_hf,rxdataF);
nr_pbch_channel_estimation(ue,&ue->frame_parms, estimateSz, dl_ch_estimates, dl_ch_estimates_time,
proc,i,i-pbch_initial_symbol,temp_ptr->i_ssb,temp_ptr->n_hf,rxdataF,false, frame_parms->Nid_cell);
stop_meas(&ue->dlsch_channel_estimation_stats);
fapiPbch_t result = {0};
......
#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 const int16_t sl_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 sl_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 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];
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
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;
#endif
#ifdef SL_DEBUG
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.
// Computing cross-correlation at peak on half the symbol size for first half of data
c32_t r1 = dot_product((c16_t *)pss_for_correlation[pss_source],
(c16_t *)&(rxdata[0][peak_position + frame_index * sl_fp->samples_per_frame]),
sl_fp->ofdm_symbol_size>>1,
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((c16_t *)pss_for_correlation[pss_source] + (sl_fp->ofdm_symbol_size >> 1),
(c16_t *)&(rxdata[0][peak_position + frame_index * sl_fp->samples_per_frame]) + (sl_fp->ofdm_symbol_size >> 1),
sl_fp->ofdm_symbol_size >> 1,
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;
int32_t metric, metric_re;
int16_t *d;
uint16_t Nid1 = 0;
uint8_t phase;
int16_t *sss;
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];
int16_t *pss_ext2,*sss_ext2;
int16_t tmp_re,tmp_im,tmp_re2,tmp_im2;
int32_t amp, shift;
//2 Symbols each for PSS and SSS
for (int j=0; j<SL_NR_NUM_PSS_OR_SSS_SYMBOLS;j++) {
int16_t *sss_ext3 = (int16_t*)&sss_ext[aarx][j][0];
sss_ext2 = (int16_t*)&sss_ext[aarx][j][0];
pss_ext2 = (int16_t*)&pss_ext[aarx][j][0];
for (int i = 0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
// This is H*(PSS) = R* \cdot PSS
tmp_re = pss_ext2[i*2] * pss[i];
tmp_im = -pss_ext2[i*2+1] * pss[i];
amp = (((int32_t)tmp_re)*tmp_re) + ((int32_t)tmp_im)*tmp_im;
shift = log2_approx(amp)/2;
// This is R(SSS) \cdot H*(PSS)
tmp_re2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[i*2])>>shift) - ((tmp_im * (int32_t)sss_ext2[i*2+1]>>shift)));
tmp_im2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[i*2+1])>>shift) + ((tmp_im * (int32_t)sss_ext2[i*2]>>shift)));
// MRC on RX antennas
// sss_ext now contains the compensated SSS
if (aarx==0) {
sss_ext3[i<<1] = tmp_re2;
sss_ext3[1+(i<<1)] = tmp_im2;
} 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;
sss = (int16_t*)&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
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]*(((sl_phase_re_nr[phase]*sss[2*i])>>15) - ((sl_phase_im_nr[phase]*sss[2*i+1])>>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.
int 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;
#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);
if (ret == 0) { // 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;
UE->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 (ret == 0) break;
}
if (ret!=0) { // 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 ret;
}
......@@ -230,12 +230,13 @@ 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],
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) {
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];
......@@ -272,7 +273,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 +335,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++) {
......
/*
* 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"
//#define DEBUG_PSBCH
//Reuse already existing PBCH functions
extern int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
NR_DL_FRAME_PARMS *frame_parms,
int nb_re);
extern void nr_pbch_channel_compensation(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],
int nb_re,
struct complex16 rxdataF_comp[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
NR_DL_FRAME_PARMS *frame_parms,
uint8_t output_shift);
extern 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);
extern void nr_pbch_quantize(int16_t *pbch_llr8,
int16_t *pbch_llr,
uint16_t len);
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;
int16_t psbch_e_rx[SL_NR_POLAR_PSBCH_E_NORMAL_CP]= {0};
int16_t psbch_unClipped[SL_NR_POLAR_PSBCH_E_NORMAL_CP]= {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];
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_ext[frame_parms->nb_antennas_rx][nb_re];
//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];
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);
//Unnecessary copy. Used only for SCOPE ... TBD... to remove this.
memcpy(psbch_unClipped + psbch_e_rx_idx, rxdataF_comp[0], SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL*sizeof(int16_t));
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;
}
/*
* 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"
/*
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.
*/
//#define SL_DEBUG
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
}
......@@ -423,6 +423,21 @@ 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);
int sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, int num_frames);
/**@}*/
#endif
......@@ -696,3 +696,106 @@ 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;
int16_t *pss_F = NULL; // IQ samples in freq domain
int32_t *pss_T = NULL;
uint16_t k = 0;
pss_F = malloc16_clear(2*sizeof(int16_t) * sl_fp->ofdm_symbol_size);
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 * 2 * sizeof(pss_F[0]));
for (int i=0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
pss_F[2*k] = (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),
pss_F, /* 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
free(pss_F);
}
......@@ -535,3 +535,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
}
......@@ -237,6 +237,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,
......
......@@ -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>
......@@ -612,6 +613,10 @@ typedef struct PHY_VARS_NR_UE_s {
uint8_t *phy_sim_dlsch_b;
notifiedFIFO_t phy_config_ind;
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 {
......@@ -633,11 +638,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
......
......@@ -168,8 +168,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)
......
/*
* 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
\ No newline at end of file
......@@ -165,5 +165,28 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
void psbch_pscch_processing(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
nr_phy_data_t *phy_data);
int phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
nr_phy_data_tx_t *phy_data);
/*! \brief This function prepares the sl indication to pass to the MAC
*/
void nr_fill_sl_indication(nr_sidelink_indication_t *sl_ind,
sl_nr_rx_indication_t *rx_ind,
sl_nr_sci_indication_t *sci_ind,
UE_nr_rxtx_proc_t *proc,
PHY_VARS_NR_UE *ue,
void *phy_data);
void nr_fill_sl_rx_indication(sl_nr_rx_indication_t *rx_ind,
uint8_t pdu_type,
PHY_VARS_NR_UE *ue,
uint16_t n_pdus,
UE_nr_rxtx_proc_t *proc,
void *typeSpecific,
uint16_t rx_slss_id);
#endif
/** @}*/
......@@ -885,12 +885,15 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr
for (int i=1; i<4; i++) {
nr_slot_fep(ue,
fp,
proc,
(ssb_start_symbol+i)%(fp->symbols_per_slot),
rxdataF);
rxdataF,
link_type_dl);
start_meas(&ue->dlsch_channel_estimation_stats);
nr_pbch_channel_estimation(ue,
&ue->frame_parms,
estimateSz,
dl_ch_estimates,
dl_ch_estimates_time,
......@@ -899,7 +902,9 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr
i-1,
ssb_index&7,
ssb_slot_2 == nr_slot_rx,
rxdataF);
rxdataF,
false,
fp->Nid_cell);
stop_meas(&ue->dlsch_channel_estimation_stats);
}
......@@ -949,9 +954,11 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr
for(int j = prs_config->SymbolStart; j < (prs_config->SymbolStart+prs_config->NumPRSSymbols); j++)
{
nr_slot_fep(ue,
fp,
proc,
(j%fp->symbols_per_slot),
rxdataF);
rxdataF,
link_type_dl);
}
nr_prs_channel_estimation(gNB_id, rsc_id, i, ue, proc, fp, rxdataF);
}
......@@ -983,9 +990,11 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr
start_meas(&ue->ofdm_demod_stats);
nr_slot_fep(ue,
fp,
proc,
l,
rxdataF);
rxdataF,
link_type_dl);
}
// Hold the channel estimates in frequency domain.
......@@ -1042,9 +1051,11 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
for (uint16_t m=start_symb_sch;m<(nb_symb_sch+start_symb_sch) ; m++){
nr_slot_fep(ue,
&ue->frame_parms,
proc,
m, //to be updated from higher layer
rxdataF);
rxdataF,
link_type_dl);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDSCH, VCD_FUNCTION_OUT);
......@@ -1133,7 +1144,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
}
l_csiim[symb_idx] = ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx];
if(nr_slot_fep_done == false) {
nr_slot_fep(ue, proc, ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx], rxdataF);
nr_slot_fep(ue, &ue->frame_parms, proc, ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx], rxdataF, link_type_dl);
}
}
nr_ue_csi_im_procedures(ue, proc, rxdataF);
......@@ -1144,7 +1155,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
if ((ue->csirs_vars[gNB_id]) && (ue->csirs_vars[gNB_id]->active == 1)) {
for(int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
if(is_csi_rs_in_symbol(ue->csirs_vars[gNB_id]->csirs_config_pdu,symb)) {
nr_slot_fep(ue, proc, symb, rxdataF);
nr_slot_fep(ue, &ue->frame_parms, proc, symb, rxdataF, link_type_dl);
}
}
nr_ue_csi_rs_procedures(ue, proc, rxdataF);
......
/*
* 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
*/
#define _GNU_SOURCE
#include "PHY/defs_nr_UE.h"
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "intertask_interface.h"
#include "T.h"
#include "PHY/MODULATION/modulation_UE.h"
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
void nr_fill_sl_indication(nr_sidelink_indication_t *sl_ind,
sl_nr_rx_indication_t *rx_ind,
sl_nr_sci_indication_t *sci_ind,
UE_nr_rxtx_proc_t *proc,
PHY_VARS_NR_UE *ue,
void *phy_data)
{
memset((void*)sl_ind, 0, sizeof(nr_sidelink_indication_t));
sl_ind->gNB_index = proc->gNB_id;
sl_ind->module_id = ue->Mod_id;
sl_ind->cc_id = ue->CC_id;
sl_ind->frame_rx = proc->frame_rx;
sl_ind->slot_rx = proc->nr_slot_rx;
sl_ind->frame_tx = proc->frame_tx;
sl_ind->slot_tx = proc->nr_slot_tx;
sl_ind->phy_data = phy_data;
if (rx_ind) {
sl_ind->rx_ind = rx_ind; // hang on rx_ind instance
sl_ind->sci_ind = NULL;
}
if (sci_ind) {
sl_ind->rx_ind = NULL;
sl_ind->sci_ind = sci_ind;
}
}
void nr_fill_sl_rx_indication(sl_nr_rx_indication_t *rx_ind,
uint8_t pdu_type,
PHY_VARS_NR_UE *ue,
uint16_t n_pdus,
UE_nr_rxtx_proc_t *proc,
void *typeSpecific,
uint16_t rx_slss_id)
{
if (n_pdus > 1){
LOG_E(PHY, "In %s: multiple number of SL PDUs not supported yet...\n", __FUNCTION__);
}
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
switch (pdu_type){
case SL_NR_RX_PDU_TYPE_SLSCH:
break;
case FAPI_NR_RX_PDU_TYPE_SSB: {
sl_nr_ssb_pdu_t *ssb_pdu = &rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu;
if(typeSpecific) {
uint8_t *psbch_decoded_output = (uint8_t *)typeSpecific;
memcpy(ssb_pdu->psbch_payload, psbch_decoded_output, sizeof(4));//4 bytes of PSBCH payload bytes
ssb_pdu->rsrp_dbm = sl_phy_params->psbch.rsrp_dBm_per_RE;
ssb_pdu->rx_slss_id = rx_slss_id;
ssb_pdu->decode_status = true;
LOG_D(PHY, "SL-IND: SSB to MAC. rsrp:%d, slssid:%d, payload:%x\n",
ssb_pdu->rsrp_dbm,ssb_pdu->rx_slss_id,
*((uint32_t *)(ssb_pdu->psbch_payload)) );
}
else
ssb_pdu->decode_status = false;
}
break;
default:
break;
}
rx_ind->rx_indication_body[n_pdus -1].pdu_type = pdu_type;
rx_ind->number_pdus = n_pdus;
}
static int nr_ue_psbch_procedures(PHY_VARS_NR_UE *ue,
NR_DL_FRAME_PARMS *fp,
UE_nr_rxtx_proc_t *proc,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
nr_phy_data_t *phy_data,
c16_t rxdataF[][fp->samples_per_slot_wCP])
{
int ret = 0;
DevAssert(ue);
int frame_rx = proc->frame_rx;
int nr_slot_rx = proc->nr_slot_rx;
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
uint16_t rx_slss_id = sl_phy_params->sl_config.sl_sync_source.rx_slss_id;
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PSBCH_PROCEDURES, VCD_FUNCTION_IN);
LOG_D(PHY,"[UE %d] Frame %d Slot %d, Trying PSBCH (SLSS ID %d)\n",
ue->Mod_id,frame_rx,nr_slot_rx,
sl_phy_params->sl_config.sl_sync_source.rx_slss_id);
uint8_t decoded_pdu[4] = {0};
ret = nr_rx_psbch(ue,
proc,
estimateSz,
dl_ch_estimates,
fp,
decoded_pdu,
rxdataF,
sl_phy_params->sl_config.sl_sync_source.rx_slss_id);
nr_sidelink_indication_t sl_indication;
sl_nr_rx_indication_t rx_ind = {0};
uint16_t number_pdus = 1;
uint8_t *result = NULL;
if (ret) {
sl_phy_params->psbch.rx_errors ++;
LOG_E(PHY,"%d:%d PSBCH RX: NOK \n",proc->frame_rx, proc->nr_slot_rx);
} else {
result = decoded_pdu;
sl_phy_params->psbch.rx_ok ++;
LOG_D(PHY,"%d:%d PSBCH RX: OK \n",proc->frame_rx, proc->nr_slot_rx);
}
nr_fill_sl_indication(&sl_indication, &rx_ind, NULL, proc, ue, phy_data);
nr_fill_sl_rx_indication(&rx_ind, SL_NR_RX_PDU_TYPE_SSB, ue, number_pdus, proc, (void *)result, rx_slss_id);
if (ue->if_inst && ue->if_inst->sl_indication)
ue->if_inst->sl_indication(&sl_indication);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PSBCH_PROCEDURES, VCD_FUNCTION_OUT);
return ret;
}
void psbch_pscch_processing(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
nr_phy_data_t *phy_data)
{
int frame_rx = proc->frame_rx;
int nr_slot_rx = proc->nr_slot_rx;
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
NR_DL_FRAME_PARMS *fp = &sl_phy_params->sl_frame_params;
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX_SL, VCD_FUNCTION_IN);
start_meas(&sl_phy_params->phy_proc_sl_rx);
LOG_D(PHY," ****** Sidelink RX-Chain for Frame.Slot %d.%d ****** \n",
frame_rx%1024, nr_slot_rx);
const uint32_t rxdataF_sz = fp->samples_per_slot_wCP;
__attribute__ ((aligned(32))) c16_t rxdataF[fp->nb_antennas_rx][rxdataF_sz];
if (phy_data->sl_rx_action == SL_NR_CONFIG_TYPE_RX_PSBCH){
const int estimateSz = fp->symbols_per_slot * fp->ofdm_symbol_size;
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PSBCH, VCD_FUNCTION_IN);
LOG_D(PHY," ----- PSBCH RX TTI: frame.slot %d.%d ------ \n",
frame_rx%1024, nr_slot_rx);
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates[fp->nb_antennas_rx][estimateSz];
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[fp->nb_antennas_rx][fp->ofdm_symbol_size];
// 0 for Normal Cyclic Prefix and 1 for EXT CyclicPrefix
const int numsym = (fp->Ncp) ? SL_NR_NUM_SYMBOLS_SSB_EXT_CP
: SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
for (int sym=0; sym<numsym;) {
nr_slot_fep(ue,
fp,
proc,
sym,
rxdataF,
link_type_ul);
start_meas(&sl_phy_params->channel_estimation_stats);
nr_pbch_channel_estimation(ue,
fp,
estimateSz,
dl_ch_estimates,
dl_ch_estimates_time,
proc,
sym,
sym,
0,
0,
rxdataF,
true,
sl_phy_params->sl_config.sl_sync_source.rx_slss_id);
stop_meas(&sl_phy_params->channel_estimation_stats);
//PSBCH present in symbols 0, 5-12 for normal cp
sym = (sym == 0) ? 5 : sym + 1;
}
nr_sl_psbch_rsrp_measurements(sl_phy_params,fp, rxdataF,false);
LOG_D(PHY," ------ Decode SL-MIB: frame.slot %d.%d ------ \n",
frame_rx%1024, nr_slot_rx);
const int psbchSuccess = nr_ue_psbch_procedures(ue, fp, proc, estimateSz,
dl_ch_estimates, phy_data, rxdataF);
if (ue->no_timing_correction==0 && psbchSuccess == 0) {
LOG_D(PHY,"start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction);
nr_adjust_synch_ue(fp,
ue,
proc->gNB_id,
fp->ofdm_symbol_size,
dl_ch_estimates_time,
frame_rx,
nr_slot_rx,
0,
16384);
}
ue->apply_timing_offset = true;
LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__);
// nr_ue_rrc_measurements(ue, proc, rxdataF);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PSBCH, VCD_FUNCTION_OUT);
if (frame_rx%64 == 0) {
LOG_I(NR_PHY,"============================================\n");
LOG_I(NR_PHY,"[UE%d] %d:%d PSBCH Stats: TX %d, RX ok %d, RX not ok %d\n",
ue->Mod_id, frame_rx, nr_slot_rx,
sl_phy_params->psbch.num_psbch_tx,
sl_phy_params->psbch.rx_ok,
sl_phy_params->psbch.rx_errors);
LOG_I(NR_PHY,"============================================\n");
}
}
}
int phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
nr_phy_data_tx_t *phy_data)
{
int slot_tx = proc->nr_slot_tx;
int frame_tx = proc->frame_tx;
int tx_action = 0;
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
NR_DL_FRAME_PARMS *fp = &sl_phy_params->sl_frame_params;
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_SL,VCD_FUNCTION_IN);
const int samplesF_per_slot = NR_SYMBOLS_PER_SLOT * fp->ofdm_symbol_size;
c16_t txdataF_buf[fp->nb_antennas_tx * samplesF_per_slot] __attribute__((aligned(32)));
memset(txdataF_buf, 0, sizeof(txdataF_buf));
c16_t *txdataF[fp->nb_antennas_tx]; /* workaround to be compatible with current txdataF usage in all tx procedures. */
for(int i=0; i< fp->nb_antennas_tx; ++i)
txdataF[i] = &txdataF_buf[i * samplesF_per_slot];
LOG_D(PHY,"****** start Sidelink TX-Chain for AbsSubframe %d.%d ******\n",
frame_tx, slot_tx);
start_meas(&sl_phy_params->phy_proc_sl_tx);
if (phy_data->sl_tx_action == SL_NR_CONFIG_TYPE_TX_PSBCH) {
sl_nr_tx_config_psbch_pdu_t *psbch_vars = &phy_data->psbch_vars;
nr_tx_psbch(ue, frame_tx, slot_tx, psbch_vars, txdataF);
sl_phy_params->psbch.num_psbch_tx ++;
if (frame_tx%64 == 0) {
LOG_I(NR_PHY,"============================================\n");
LOG_I(NR_PHY,"[UE%d] %d:%d PSBCH Stats: TX %d, RX ok %d, RX not ok %d\n",
ue->Mod_id, frame_tx, slot_tx,
sl_phy_params->psbch.num_psbch_tx,
sl_phy_params->psbch.rx_ok,
sl_phy_params->psbch.rx_errors);
LOG_I(NR_PHY,"============================================\n");
}
tx_action = 1;
}
if (tx_action) {
LOG_D(PHY, "Sending Uplink data \n");
nr_ue_pusch_common_procedures(ue,
proc->nr_slot_tx,
fp,
fp->nb_antennas_tx,
txdataF);
}
LOG_D(PHY,"****** end Sidelink TX-Chain for AbsSubframe %d.%d ******\n",
frame_tx, slot_tx);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_SL, VCD_FUNCTION_OUT);
stop_meas(&sl_phy_params->phy_proc_sl_tx);
return tx_action;
}
......@@ -787,12 +787,13 @@ int main(int argc, char **argv)
proc.gNB_id = 0;
for (int i=UE->symbol_offset+1; i<UE->symbol_offset+4; i++) {
nr_slot_fep(UE,
frame_parms,
&proc,
i%frame_parms->symbols_per_slot,
rxdataF);
rxdataF, link_type_dl);
nr_pbch_channel_estimation(UE,estimateSz, dl_ch_estimates, dl_ch_estimates_time, &proc,
i%frame_parms->symbols_per_slot,i-(UE->symbol_offset+1),ssb_index%8,n_hf,rxdataF);
nr_pbch_channel_estimation(UE,&UE->frame_parms, estimateSz, dl_ch_estimates, dl_ch_estimates_time, &proc,
i%frame_parms->symbols_per_slot,i-(UE->symbol_offset+1),ssb_index%8,n_hf,rxdataF,false,frame_parms->Nid_cell);
}
fapiPbch_t result;
......
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "common/config/config_userapi.h"
#include "common/ran_context.h"
#include "PHY/types.h"
#include "PHY/defs_nr_common.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/defs_gNB.h"
#include "PHY/phy_vars.h"
#include "NR_MasterInformationBlockSidelink.h"
#include "PHY/INIT/phy_init.h"
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h"
#include "openair1/SIMULATION/TOOLS/sim.h"
#include "common/utils/nr/nr_common.h"
#include "openair2/RRC/NR/nr_rrc_extern.h"
#include "openair2/RRC/LTE/rrc_vars.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/INIT/nr_phy_init.h"
#include "SIMULATION/RF/rf.h"
#include "common/utils/load_module_shlib.h"
#include "PHY/MODULATION/nr_modulation.h"
#include "NR_SL-SSB-TimeAllocation-r16.h"
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); }
void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); }
void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); }
void exit_function(const char* file, const char* function, const int line, const char* s, const int assert) {
const char * msg= s==NULL ? "no comment": s;
printf("Exiting at: %s:%d %s(), %s\n", file, line, function, msg);
exit(-1);
}
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { return 1; }
// to solve link errors
double cpuf;
//void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {}
void get_num_re_dmrs(nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
uint8_t *nb_dmrs_re_per_rb,
uint16_t *number_dmrs_symbols){}
uint64_t downlink_frequency[1][1];
int32_t uplink_frequency_offset[1][1];
THREAD_STRUCT thread_struct;
instance_t DUuniqInstance=0;
instance_t CUuniqInstance=0;
openair0_config_t openair0_cfg[1];
RAN_CONTEXT_t RC;
int oai_exit = 0;
char *uecap_file;
void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB_index)
{
return;
}
int8_t nr_mac_rrc_data_req_ue(const module_id_t Mod_idP,
const int CC_id,
const uint8_t gNB_id,
const frame_t frameP,
const rb_id_t Srb_id,
uint8_t *buffer_pP)
{
return 0;
}
nr_bler_struct nr_bler_data[NR_NUM_MCS];
void get_nrUE_params(void) { return;}
uint8_t check_if_ue_is_sl_syncsource() {return 0;}
//////////////////////////////////////////////////////////////////////////
static void prepare_mib_bits(uint8_t *buf, uint32_t frame_tx, uint32_t slot_tx) {
NR_MasterInformationBlockSidelink_t *sl_mib;
asn_enc_rval_t enc_rval;
void *buffer = (void *)buf;
sl_mib = CALLOC(1, sizeof(NR_MasterInformationBlockSidelink_t));
sl_mib->inCoverage_r16 = 0;//TRUE;
// allocate buffer for 7 bits slotnumber
sl_mib->slotIndex_r16.size = 1;
sl_mib->slotIndex_r16.buf = CALLOC(1, sl_mib->slotIndex_r16.size);
sl_mib->slotIndex_r16.bits_unused = sl_mib->slotIndex_r16.size*8 - 7;
sl_mib->slotIndex_r16.buf[0] = slot_tx << sl_mib->slotIndex_r16.bits_unused;
sl_mib->directFrameNumber_r16.size = 2;
sl_mib->directFrameNumber_r16.buf = CALLOC(1, sl_mib->directFrameNumber_r16.size);
sl_mib->directFrameNumber_r16.bits_unused = sl_mib->directFrameNumber_r16.size*8 - 10;
sl_mib->directFrameNumber_r16.buf[0] = frame_tx >> (8 - sl_mib->directFrameNumber_r16.bits_unused);
sl_mib->directFrameNumber_r16.buf[1] = frame_tx << sl_mib->directFrameNumber_r16.bits_unused;
enc_rval = uper_encode_to_buffer(&asn_DEF_NR_MasterInformationBlockSidelink,
NULL,
(void *)sl_mib,
buffer,
100);
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n",
enc_rval.failed_type->name, enc_rval.encoded);
asn_DEF_NR_MasterInformationBlockSidelink.op->free_struct(&asn_DEF_NR_MasterInformationBlockSidelink, sl_mib, ASFM_FREE_EVERYTHING);
}
static int test_rx_mib(uint8_t *decoded_output, uint16_t frame, uint16_t slot) {
uint32_t sl_mib = *(uint32_t *)decoded_output;
uint32_t fn = 0, sl = 0;
fn = (((sl_mib & 0x0700) >> 1) | ((sl_mib & 0xFE0000) >> 17));
sl = (((sl_mib & 0x010000) >> 10) | ((sl_mib & 0xFC000000) >> 26));
printf("decoded output:%x, TX %d:%d, timing decoded from sl-MIB %d:%d\n",
*(uint32_t *)decoded_output, frame, slot, fn, sl);
if (frame == fn && slot == sl)
return 0;
return -1;
}
//////////////////////////////////////////////////////////////////////////
static void configure_NR_UE(PHY_VARS_NR_UE *UE, int mu, int N_RB) {
fapi_nr_config_request_t config;
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
config.ssb_config.scs_common = mu;
config.cell_config.frame_duplex_type = TDD;
config.carrier_config.dl_grid_size[mu] = N_RB;
config.carrier_config.ul_grid_size[mu] = N_RB;
config.carrier_config.dl_frequency = 0;
config.carrier_config.uplink_frequency = 0;
int band;
if (mu == 1) band = 78;
if (mu == 0) band = 34;
nr_init_frame_parms_ue(fp, &config, band);
fp->ofdm_offset_divisor = 8;
nr_dump_frame_parms(fp);
if (init_nr_ue_signal(UE, 1) != 0) {
printf("Error at UE NR initialisation\n");
exit(-1);
}
}
static void sl_init_frame_parameters(PHY_VARS_NR_UE *UE) {
NR_DL_FRAME_PARMS *nr_fp = &UE->frame_parms;
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
memcpy(sl_fp, nr_fp, sizeof(NR_DL_FRAME_PARMS));
sl_fp->ofdm_offset_divisor = 8; // What is this used for?
sl_fp->att_tx = 1;
sl_fp->att_rx = 1;
// band47 //UL freq will be set to Sidelink freq
sl_fp->ul_CarrierFreq = 5880000000;
sl_fp->ssb_start_subcarrier = UE->SL_UE_PHY_PARAMS.sl_config.sl_bwp_config.sl_ssb_offset_point_a;
sl_fp->Nid_cell = UE->SL_UE_PHY_PARAMS.sl_config.sl_sync_source.rx_slss_id;
#ifdef DEBUG_INIT
LOG_I(PHY, "Dumping Sidelink Frame Parameters\n");
nr_dump_frame_parms(sl_fp);
#endif
}
static void configure_SL_UE(PHY_VARS_NR_UE *UE, int mu, int N_RB, int ssb_offset, int slss_id) {
sl_nr_phy_config_request_t *config = &UE->SL_UE_PHY_PARAMS.sl_config;
NR_DL_FRAME_PARMS *fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
config->sl_bwp_config.sl_scs = mu;
config->sl_bwp_config.sl_ssb_offset_point_a = ssb_offset;
config->sl_carrier_config.sl_bandwidth = N_RB;
config->sl_carrier_config.sl_grid_size = 106;
config->sl_sync_source.rx_slss_id = slss_id;
sl_init_frame_parameters(UE);
sl_ue_phy_init(UE);
init_symbol_rotation(fp);
init_timeshift_rotation(fp);
LOG_I(PHY, "Dumping Sidelink Frame Parameters\n");
nr_dump_frame_parms(fp);
}
static int freq_domain_loopback(PHY_VARS_NR_UE *UE_tx, PHY_VARS_NR_UE *UE_rx,
int frame, int slot,
nr_phy_data_tx_t *phy_data) {
sl_nr_ue_phy_params_t *sl_ue1 = &UE_tx->SL_UE_PHY_PARAMS;
sl_nr_ue_phy_params_t *sl_ue2 = &UE_rx->SL_UE_PHY_PARAMS;
printf("\nPSBCH SIM -F: %d:%d slss id TX UE:%d, RX UE:%d\n",
frame, slot,phy_data->psbch_vars.tx_slss_id,
sl_ue2->sl_config.sl_sync_source.rx_slss_id);
NR_DL_FRAME_PARMS *fp = &sl_ue1->sl_frame_params;
const int samplesF_per_slot = NR_SYMBOLS_PER_SLOT * fp->ofdm_symbol_size;
c16_t txdataF_buf[fp->nb_antennas_tx * samplesF_per_slot] __attribute__((aligned(32)));
memset(txdataF_buf, 0, sizeof(txdataF_buf));
c16_t *txdataF[fp->nb_antennas_tx]; /* workaround to be compatible with current txdataF usage in all tx procedures. */
for(int i=0; i< fp->nb_antennas_tx; ++i)
txdataF[i] = &txdataF_buf[i * samplesF_per_slot];
nr_tx_psbch(UE_tx,frame, slot, &phy_data->psbch_vars, txdataF);
int estimateSz = sl_ue2->sl_frame_params.samples_per_slot_wCP;
__attribute__ ((aligned(32))) struct complex16 rxdataF[1][estimateSz];
for (int i=0; i<sl_ue1->sl_frame_params.samples_per_slot_wCP; i++) {
struct complex16 *txdataF_ptr = (struct complex16 *)&txdataF[0][i];
struct complex16 *rxdataF_ptr = (struct complex16 *)&rxdataF[0][i];
rxdataF_ptr->r = txdataF_ptr->r;
rxdataF_ptr->i = txdataF_ptr->i;
//printf("r,i TXDATAF[%d]- %d:%d, RXDATAF[%d]- %d:%d\n",
// i, txdataF_ptr->r, txdataF_ptr->i, i, txdataF_ptr->r, txdataF_ptr->i);
}
uint8_t err_status = 0;
UE_nr_rxtx_proc_t proc;
proc.frame_rx = frame;
proc.nr_slot_rx = slot;
struct complex16 dl_ch_estimates[1][estimateSz];
uint8_t decoded_output[4] = {0};
LOG_I(PHY,"DEBUG: HIJACKING DL CHANNEL ESTIMATES.\n");
for (int s=0; s<14; s++) {
for (int j=0; j<sl_ue2->sl_frame_params.ofdm_symbol_size; j++) {
struct complex16 *dlch = (struct complex16 *)(&dl_ch_estimates[0][s*sl_ue2->sl_frame_params.ofdm_symbol_size]);
dlch[j].r = 128;
dlch[j].i = 0;
}
}
err_status = nr_rx_psbch(UE_rx,
&proc,
estimateSz,
dl_ch_estimates,
&sl_ue2->sl_frame_params,
decoded_output,
rxdataF,
sl_ue2->sl_config.sl_sync_source.rx_slss_id);
int error_payload = 0;
error_payload = test_rx_mib(decoded_output, frame, slot);
if (err_status == 0 || error_payload == 0) {
LOG_I(PHY,"---------PSBCH -F TEST OK.\n");
return 0;
}
LOG_E(PHY, "--------PSBCH -F TEST NOK. FAIL.\n");
return -1;
}
PHY_VARS_NR_UE *UE_TX; // for tx
PHY_VARS_NR_UE *UE_RX; // for rx
double cpuf;
configmodule_interface_t *uniqCfg = NULL;
int main(int argc, char **argv) {
char c;
int test_freqdomain_loopback = 0,test_slss_search = 0;
int frame = 5, slot = 10, frame_tx = 0, slot_tx = 0;
int loglvl = OAILOG_INFO;
uint16_t slss_id = 336, ssb_offset = 0;
double snr1 = 2.0, snr0 = 2.0, SNR;
double sigma2 = 0.0, sigma2_dB = 0.0;
double cfo=0, ip =0.0;
SCM_t channel_model=AWGN;//Rayleigh1_anticorr;
int N_RB_DL=106,mu=1;
uint16_t errors = 0, n_trials = 1;
int frame_length_complex_samples;
//int frame_length_complex_samples_no_prefix;
NR_DL_FRAME_PARMS *frame_parms;
int seed = 0;
cpuf = get_cpu_freq_GHz();
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
exit_fun("[NR_PSBCHSIM] Error, configuration module init failed\n");
}
randominit(0);
while ((c = getopt(argc, argv, "c:hn:o:s:FIL:N:R:S:T:")) != -1) {
printf("SIDELINK PSBCH SIM: handling optarg %c\n",c);
switch (c) {
case 'c':
cfo = atof(optarg);
printf("Setting CFO to %f Hz\n",cfo);
break;
case 'g':
switch((char)*optarg) {
case 'A':
channel_model=SCM_A;
break;
case 'B':
channel_model=SCM_B;
break;
case 'C':
channel_model=SCM_C;
break;
case 'D':
channel_model=SCM_D;
break;
case 'E':
channel_model=EPA;
break;
case 'F':
channel_model=EVA;
break;
case 'G':
channel_model=ETU;
break;
default:
printf("Unsupported channel model! Exiting.\n");
exit(-1);
}
break;
case 'n':
n_trials = atoi(optarg);
break;
case 'o':
ssb_offset = atoi(optarg);
printf("SIDELINK PSBCH SIM: ssb offset from pointA:%d\n",ssb_offset);
break;
case 's':
slss_id = atoi(optarg);
printf("SIDELINK PSBCH SIM: slss_id from arg:%d\n",slss_id);
AssertFatal(slss_id >= 0 && slss_id <= 671,"SLSS ID not within Range 0-671\n");
break;
case 'F':
test_freqdomain_loopback = 1;
break;
case 'I':
test_slss_search = 1;
printf("SIDELINK PSBCH SIM: SLSS search will be tested\n");
break;
case 'L':
loglvl = atoi(optarg);
break;
case 'N':
snr0 = atoi(optarg);
snr1 = snr0;
printf("Setting SNR0 to %f. Test uses this SNR as target SNR\n",snr0);
break;
case 'R':
N_RB_DL = atoi(optarg);
printf("SIDELINK PSBCH SIM: N_RB_DL:%d\n",N_RB_DL);
break;
case 'S':
snr1 = atof(optarg);
printf("Setting SNR1 to %f. Test will run until this SNR as target SNR\n",snr1);
AssertFatal(snr1 <= snr0, "Test runs SNR down, set snr1 to a lower value than %f\n", snr0);
break;
case 'T':
frame = atoi(optarg);
slot = atoi(argv[optind]);
printf("PSBCH SIM: frame timing- %d:%d\n",frame, slot);
break;
case 'h':
default :
printf("\n\nSIDELINK PSBCH SIM OPTIONS LIST - hus:FL:T:\n");
printf("-h: HELP\n");
printf("-c Carrier frequency offset in Hz\n");
printf("-n Number of trials\n");
printf("-o ssb offset from PointA - indicates ssb_start subcarrier\n");
printf("-s: set Sidelink sync id slss_id. ex -s 100\n");
printf("-F: Run PSBCH frequency domain loopback test of the samples\n");
printf("-I: Sidelink SLSS search will be tested.\n");
printf("-L: Set Log Level.\n");
printf("-N: Test with Noise. target SNR0 eg -N 10\n");
printf("-R N_RB_DL\n");
printf("-S Ending SNR, runs from SNR0 to SNR1\n");
printf("-T: Frame,Slot to be sent in sl-MIB eg -T 4 2\n");
return 1;
}
}
randominit(seed);
logInit();
set_glog(loglvl);
double fs=0, eps;
double scs = 30000;
double bw = 100e6;
switch (mu) {
case 1:
scs = 30000;
if (N_RB_DL == 217) {
fs = 122.88e6;
bw = 80e6;
}
else if (N_RB_DL == 245) {
fs = 122.88e6;
bw = 90e6;
}
else if (N_RB_DL == 273) {
fs = 122.88e6;
bw = 100e6;
}
else if (N_RB_DL == 106) {
fs = 61.44e6;
bw = 40e6;
}
else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL);
break;
case 3:
scs = 120000;
if (N_RB_DL == 66) {
fs = 122.88e6;
bw = 100e6;
}
else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL);
break;
}
// cfo with respect to sub-carrier spacing
eps = cfo/scs;
// computation of integer and fractional FO to compare with estimation results
int IFO;
if(eps!=0.0){
printf("Introducing a CFO of %lf relative to SCS of %d kHz\n",eps,(int)(scs/1000));
if (eps>0)
IFO=(int)(eps+0.5);
else
IFO=(int)(eps-0.5);
printf("FFO = %lf; IFO = %d\n",eps-IFO,IFO);
}
channel_desc_t *UE2UE;
int n_tx = 1, n_rx = 1;
UE2UE = new_channel_desc_scm(n_tx,
n_rx,
channel_model,
fs,
0,
bw,
300e-9,
0.0,
CORR_LEVEL_LOW,
0,
0,
0,
0);
if (UE2UE==NULL) {
printf("Problem generating channel model. Exiting.\n");
exit(-1);
}
/*****configure UE *************************/
UE_TX = calloc(1, sizeof(PHY_VARS_NR_UE));
UE_RX = calloc(1, sizeof(PHY_VARS_NR_UE));
LOG_I(PHY, "Configure UE-TX and sidelink UE-TX.\n");
configure_NR_UE(UE_TX, mu, N_RB_DL);
configure_SL_UE(UE_TX, mu, N_RB_DL,ssb_offset, 0xFFFF);
LOG_I(PHY, "Configure UE-RX and sidelink UE-RX.\n");
configure_NR_UE(UE_RX, mu, N_RB_DL);
UE_RX->is_synchronized = (test_slss_search) ? 0 : 1;
configure_SL_UE(UE_RX, mu, N_RB_DL,ssb_offset, slss_id);
/*****************************************/
sl_nr_ue_phy_params_t *sl_uetx = &UE_TX->SL_UE_PHY_PARAMS;
sl_nr_ue_phy_params_t *sl_uerx = &UE_RX->SL_UE_PHY_PARAMS;
frame_parms = &sl_uetx->sl_frame_params;
frame_tx = frame % 1024;
slot_tx = slot % frame_parms->slots_per_frame;
frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
//frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP;
double **s_re,**s_im,**r_re,**r_im;
s_re = malloc(2*sizeof(double*));
s_im = malloc(2*sizeof(double*));
r_re = malloc(2*sizeof(double*));
r_im = malloc(2*sizeof(double*));
s_re[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
s_im[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
r_re[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
r_im[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
if(eps!=0.0)
UE_RX->UE_fo_compensation = 1; // if a frequency offset is set then perform fo estimation and compensation
UE_nr_rxtx_proc_t proc;
proc.frame_tx = frame;
proc.nr_slot_tx = slot;
nr_phy_data_tx_t phy_data_tx;
phy_data_tx.psbch_vars.tx_slss_id = slss_id;
uint8_t sl_mib[4] = {0};
prepare_mib_bits(sl_mib,frame, slot);
memcpy(phy_data_tx.psbch_vars.psbch_payload,sl_mib, 4);
phy_data_tx.sl_tx_action = SL_NR_CONFIG_TYPE_TX_PSBCH;
proc.frame_rx = frame;
proc.nr_slot_rx = slot;
nr_phy_data_t phy_data_rx;
phy_data_rx.sl_rx_action = SL_NR_CONFIG_TYPE_RX_PSBCH;
if (test_freqdomain_loopback) {
errors += freq_domain_loopback(UE_TX, UE_RX, frame_tx, slot_tx, &phy_data_tx);
}
printf("\nSidelink TX UE - Frame.Slot %d.%d SLSS id:%d\n",
frame, slot,phy_data_tx.psbch_vars.tx_slss_id);
printf("Sidelink RX UE - Frame.Slot %d.%d SLSS id:%d\n",
proc.frame_rx, proc.nr_slot_rx,
sl_uerx->sl_config.sl_sync_source.rx_slss_id);
phy_procedures_nrUE_SL_TX(UE_TX, &proc, &phy_data_tx);
for (SNR=snr0; SNR>=snr1; SNR-=1) {
for (int trial=0; trial<n_trials; trial++) {
for (int i=0; i<frame_length_complex_samples; i++) {
for (int aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
struct complex16 *txdata_ptr = (struct complex16 *)&UE_TX->common_vars.txData[aa][i];
r_re[aa][i] = (double)txdata_ptr->r;
r_im[aa][i] = (double)txdata_ptr->i;
}
}
LOG_M("txData0.m","txd0", UE_TX->common_vars.txData[0],frame_parms->samples_per_frame,1,1);
//AWGN
sigma2_dB = 20*log10((double)AMP/4)-SNR;
sigma2 = pow(10,sigma2_dB/10);
//printf("sigma2 %f (%f dB), tx_lev %f (%f dB)\n",sigma2,sigma2_dB,txlev,10*log10((double)txlev));
if(eps!=0.0) {
rf_rx(r_re, // real part of txdata
r_im, // imag part of txdata
NULL, // interference real part
NULL, // interference imag part
0, // interference power
frame_parms->nb_antennas_rx, // number of rx antennas
frame_length_complex_samples, // number of samples in frame
1.0e9/fs, //sampling time (ns)
cfo, // frequency offset in Hz
0.0, // drift (not implemented)
0.0, // noise figure (not implemented)
0.0, // rx gain in dB ?
200, // 3rd order non-linearity in dB ?
&ip, // initial phase
30.0e3, // phase noise cutoff in kHz
-500.0, // phase noise amplitude in dBc
0.0, // IQ imbalance (dB),
0.0); // IQ phase imbalance (rad)
}
for (int i=0; i<frame_length_complex_samples; i++) {
for (int aa=0; aa<frame_parms->nb_antennas_rx; aa++) {
UE_RX->common_vars.rxdata[aa][i].r = (short)(r_re[aa][i] + sqrt(sigma2 / 2) * gaussdouble(0.0, 1.0));
UE_RX->common_vars.rxdata[aa][i].i = (short)(r_im[aa][i] + sqrt(sigma2 / 2) * gaussdouble(0.0, 1.0));
}
}
if (UE_RX->is_synchronized == 0) {
int ret = -1;
UE_nr_rxtx_proc_t proc={0};
//Should not have SLSS id configured. Search should find SLSS id from TX UE
UE_RX->SL_UE_PHY_PARAMS.sl_config.sl_sync_source.rx_slss_id = 0xFFFF;
ret = sl_nr_slss_search(UE_RX, &proc, 1);
printf("Sidelink SLSS search returns %d\n",ret);
if (ret!=0) sl_uerx->psbch.rx_errors = 1;
else {
AssertFatal(UE_RX->SL_UE_PHY_PARAMS.sync_params.N_sl_id == slss_id,
"DETECTED INCORRECT SLSS ID in SEARCH.CHECK id:%d\n", UE_RX->SL_UE_PHY_PARAMS.sync_params.N_sl_id);
sl_uerx->psbch.rx_ok = 1;
}
} else psbch_pscch_processing(UE_RX,&proc,&phy_data_rx);
} //noise trials
printf("Runs:%d SNR %f: SLSS Search:%d crc ERRORs = %d, OK = %d\n",
n_trials, SNR, !UE_RX->is_synchronized,
sl_uerx->psbch.rx_errors, sl_uerx->psbch.rx_ok);
errors += sl_uerx->psbch.rx_errors;
sl_uerx->psbch.rx_errors = 0;
sl_uerx->psbch.rx_ok = 0;
} // NSR
if (errors == 0)
LOG_I(PHY,"PSBCH test OK\n");
else
LOG_E(PHY,"PSBCH test NOT OK\n");
free_channel_desc_scm(UE2UE);
free(s_re[0]);
free(s_im[0]);
free(r_re[0]);
free(r_im[0]);
free(s_re);
free(s_im);
free(r_re);
free(r_im);
term_nr_ue_signal(UE_TX, 1);
term_nr_ue_signal(UE_RX, 1);
free(UE_TX);
free(UE_RX);
logTerm();
loader_reset();
return errors;
}
......@@ -98,7 +98,7 @@ typedef struct {
uint32_t gNB_index;
/// component carrier id
int cc_id;
/// frame
/// frame rx
frame_t frame_rx;
/// slot rx
uint32_t slot_rx;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment