Integrate periodic SSB measurement in SRSUE and fix related defects

This commit is contained in:
Xavier Arteaga 2021-05-10 15:14:54 +02:00 committed by Xavier Arteaga
parent 5e41e99f08
commit a57336d64f
13 changed files with 475 additions and 85 deletions

View File

@ -16,7 +16,7 @@
#include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/pdcp_interface_types.h"
#include "srsran/interfaces/rlc_interface_types.h"
#include "srsran/interfaces/rrc_interface_types.h"
#include "srsran/interfaces/rrc_nr_interface_types.h"
#include "srsran/interfaces/sched_interface.h"
/************************
@ -55,6 +55,7 @@ struct zp_csi_rs_res_s;
struct nzp_csi_rs_res_s;
struct pdsch_serving_cell_cfg_s;
struct freq_info_dl_s;
struct serving_cell_cfg_common_s;
} // namespace rrc_nr
} // namespace asn1
@ -106,6 +107,8 @@ bool make_phy_zp_csi_rs_resource(const asn1::rrc_nr::zp_csi_rs_res_s& zp_csi_rs_
bool make_phy_nzp_csi_rs_resource(const asn1::rrc_nr::nzp_csi_rs_res_s& nzp_csi_rs_res,
srsran_csi_rs_nzp_resource_t* csi_rs_nzp_resource);
bool make_phy_carrier_cfg(const asn1::rrc_nr::freq_info_dl_s& freq_info_dl, srsran_carrier_nr_t* carrier_nr);
bool make_phy_ssb_cfg(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg, phy_cfg_nr_t::ssb_cfg_t* ssb);
/***************************
* MAC Config
**************************/

View File

@ -15,6 +15,7 @@
#include "srsran/config.h"
#include "srsran/srsran.h"
#include <array>
#include <string>
namespace srsran {
@ -24,6 +25,15 @@ namespace srsran {
**************************/
struct phy_cfg_nr_t {
/**
* SSB configuration
*/
struct ssb_cfg_t {
uint32_t periodicity_ms;
std::array<bool, SRSRAN_SSB_NOF_POSITION> position_in_burst;
srsran_subcarrier_spacing_t scs;
};
srsran_tdd_config_nr_t tdd = {};
srsran_sch_hl_cfg_nr_t pdsch = {};
srsran_sch_hl_cfg_nr_t pusch = {};
@ -33,6 +43,7 @@ struct phy_cfg_nr_t {
srsran_ue_dl_nr_harq_ack_cfg_t harq_ack = {};
srsran_csi_hl_cfg_t csi = {};
srsran_carrier_nr_t carrier = {};
ssb_cfg_t ssb;
phy_cfg_nr_t() {}

View File

@ -192,6 +192,11 @@ extern "C" {
*/
#define SRSRAN_SSB_NOF_RE (SRSRAN_SSB_BW_SUBC * SRSRAN_SSB_DURATION_NSYMB)
/**
* @brief Symbol index with extended CP
*/
#define SRSRAN_EXT_CP_SYMBOL(SCS) (7U << (uint32_t)(SCS))
typedef enum SRSRAN_API {
srsran_coreset_mapping_type_non_interleaved = 0,
srsran_coreset_mapping_type_interleaved,

View File

@ -19,7 +19,7 @@
* @brief Descibes the NR PBCH message
*/
typedef struct SRSRAN_API {
// TBD
void* TBD;
} srsran_pbch_msg_nr_t;
#endif // SRSRAN_PBCH_NR_H

View File

@ -34,6 +34,11 @@
*/
#define SRSRAN_SSB_DEFAULT_BETA 1.0f
/**
* @brief Maximum number of SSB positions in burst. Defined in TS 38.331 ServingCellConfigCommon, ssb-PositionsInBurst
*/
#define SRSRAN_SSB_NOF_POSITION 64
/**
* @brief Describes SSB object initialization arguments
*/
@ -51,12 +56,17 @@ typedef struct SRSRAN_API {
*/
typedef struct SRSRAN_API {
double srate_hz; ///< Current sampling rate in Hz
double freq_offset_hz; ///< SSB base-band frequency offset
double center_freq_hz; ///< Base-band center frequency in Hz
double ssb_freq_hz; ///< SSB center frequency
srsran_subcarrier_spacing_t scs; ///< SSB configured Subcarrier spacing
float beta_pss; ////< PSS power allocation
float beta_sss; ////< SSS power allocation
float beta_pbch; ////< PBCH power allocation
float beta_pbch_dmrs; ////< PBCH DMRS power allocation
srsran_ssb_patern_t pattern; ///< SSB pattern as defined in TS 38.313 section 4.1 Cell search
bool position[SRSRAN_SSB_NOF_POSITION]; ///< Indicates the time domain positions of the transmitted SS-blocks
srsran_duplex_mode_t duplex_mode; ///< Set to true if the spectrum is paired (FDD)
uint32_t periodicity_ms; ///< SSB periodicity in ms
float beta_pss; ////< PSS power allocation
float beta_sss; ////< SSS power allocation
float beta_pbch; ////< PBCH power allocation
float beta_pbch_dmrs; ////< PBCH DMRS power allocation
} srsran_ssb_cfg_t;
/**
@ -67,12 +77,12 @@ typedef struct SRSRAN_API {
srsran_ssb_cfg_t cfg; ///< Stores last configuration
/// Sampling rate dependent parameters
float scs_hz; ///< Subcarrier spacing in Hz
uint32_t max_symbol_sz; ///< Maximum symbol size given the minimum supported SCS and sampling rate
uint32_t symbol_sz; ///< Current SSB symbol size (for the given base-band sampling rate)
int32_t offset; ///< Current SSB integer offset (multiple of SCS)
uint32_t cp0_sz; ///< First symbol cyclic prefix size
uint32_t cp_sz; ///< Other symbol cyclic prefix size
float scs_hz; ///< Subcarrier spacing in Hz
uint32_t max_symbol_sz; ///< Maximum symbol size given the minimum supported SCS and sampling rate
uint32_t symbol_sz; ///< Current SSB symbol size (for the given base-band sampling rate)
int32_t f_offset; ///< Current SSB integer frequency offset (multiple of SCS)
uint32_t t_offset; ///< Current SSB integer time offset (number of samples)
uint32_t cp_sz[SRSRAN_SSB_DURATION_NSYMB]; ///< CP length for each SSB symbol
/// Internal Objects
srsran_dft_plan_t ifft; ///< IFFT object for modulating the SSB
@ -111,6 +121,14 @@ SRSRAN_API int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg);
*/
SRSRAN_API int srsran_ssb_decode_pbch(srsran_ssb_t* q, const cf_t* in, srsran_pbch_msg_nr_t* msg);
/**
* @brief Decides if the SSB object is configured and a given subframe is configured for SSB transmission
* @param q SSB object
* @param sf_idx Subframe index within the radio frame
* @return true if the SSB object is configured and SSB is transmitted, false otherwise
*/
SRSRAN_API bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx);
/**
* @brief Adds SSB to a given signal in time domain
* @param q SSB object

View File

@ -125,6 +125,7 @@ extern "C" {
#include "srsran/phy/sync/pss.h"
#include "srsran/phy/sync/refsignal_dl_sync.h"
#include "srsran/phy/sync/sfo.h"
#include "srsran/phy/sync/ssb.h"
#include "srsran/phy/sync/sss.h"
#include "srsran/phy/sync/sync.h"

View File

@ -1245,11 +1245,36 @@ bool make_phy_nzp_csi_rs_resource(const asn1::rrc_nr::nzp_csi_rs_res_s& asn1_nzp
return true;
}
static inline srsran_subcarrier_spacing_t make_subcarrier_spacing(const subcarrier_spacing_e& asn1_scs)
{
switch (asn1_scs) {
case subcarrier_spacing_opts::options::khz15:
return srsran_subcarrier_spacing_15kHz;
case subcarrier_spacing_opts::options::khz30:
return srsran_subcarrier_spacing_30kHz;
case subcarrier_spacing_opts::options::khz60:
return srsran_subcarrier_spacing_60kHz;
case subcarrier_spacing_opts::options::khz120:
return srsran_subcarrier_spacing_120kHz;
case subcarrier_spacing_opts::options::khz240:
return srsran_subcarrier_spacing_240kHz;
case subcarrier_spacing_opts::spare3:
case subcarrier_spacing_opts::spare2:
case subcarrier_spacing_opts::spare1:
case subcarrier_spacing_opts::nulltype:
default:
asn1::log_warning("Not supported subcarrier spacing ");
break;
}
return srsran_subcarrier_spacing_invalid;
}
bool make_phy_carrier_cfg(const freq_info_dl_s& asn1_freq_info_dl, srsran_carrier_nr_t* out_carrier_nr)
{
uint32_t absolute_frequency_ssb = 0;
if (asn1_freq_info_dl.absolute_freq_ssb_present) {
absolute_frequency_ssb = asn1_freq_info_dl.absolute_freq_ssb_present;
absolute_frequency_ssb = asn1_freq_info_dl.absolute_freq_ssb;
} else {
asn1::log_warning("Option absolute_freq_ssb not present");
return false;
@ -1259,26 +1284,12 @@ bool make_phy_carrier_cfg(const freq_info_dl_s& asn1_freq_info_dl, srsran_carrie
return false;
}
srsran_subcarrier_spacing_t scs = srsran_subcarrier_spacing_15kHz;
switch (asn1_freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing) {
case subcarrier_spacing_opts::options::khz15:
scs = srsran_subcarrier_spacing_15kHz;
break;
case subcarrier_spacing_opts::options::khz30:
scs = srsran_subcarrier_spacing_30kHz;
break;
case subcarrier_spacing_opts::options::khz60:
scs = srsran_subcarrier_spacing_60kHz;
break;
case subcarrier_spacing_opts::options::khz120:
scs = srsran_subcarrier_spacing_120kHz;
break;
case subcarrier_spacing_opts::options::khz240:
scs = srsran_subcarrier_spacing_240kHz;
break;
default:
asn1::log_warning("Not supported subcarrier spacing ");
srsran_subcarrier_spacing_t scs =
make_subcarrier_spacing(asn1_freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing);
if (scs == srsran_subcarrier_spacing_invalid) {
return false;
}
// As the carrier structure requires parameters from different objects, set fields separately
out_carrier_nr->absolute_frequency_ssb = absolute_frequency_ssb;
out_carrier_nr->absolute_frequency_point_a = asn1_freq_info_dl.absolute_freq_point_a;
@ -1287,6 +1298,63 @@ bool make_phy_carrier_cfg(const freq_info_dl_s& asn1_freq_info_dl, srsran_carrie
out_carrier_nr->scs = scs;
return true;
}
template <class bitstring_t>
static inline void make_ssb_positions_in_burst(const bitstring_t& ans1_position_in_burst,
std::array<bool, SRSRAN_SSB_NOF_POSITION>& position_in_burst)
{
for (uint32_t i = 0; i < SRSRAN_SSB_NOF_POSITION; i++) {
if (i < ans1_position_in_burst.length()) {
position_in_burst[i] = ans1_position_in_burst.get(ans1_position_in_burst.length() - 1 - i);
} else {
position_in_burst[i] = false;
}
}
}
bool make_phy_ssb_cfg(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg, phy_cfg_nr_t::ssb_cfg_t* out_ssb)
{
phy_cfg_nr_t::ssb_cfg_t ssb = {};
if (serv_cell_cfg.ssb_positions_in_burst_present) {
switch (serv_cell_cfg.ssb_positions_in_burst.type()) {
case serving_cell_cfg_common_s::ssb_positions_in_burst_c_::types_opts::short_bitmap:
make_ssb_positions_in_burst(serv_cell_cfg.ssb_positions_in_burst.short_bitmap(), ssb.position_in_burst);
break;
case serving_cell_cfg_common_s::ssb_positions_in_burst_c_::types_opts::medium_bitmap:
make_ssb_positions_in_burst(serv_cell_cfg.ssb_positions_in_burst.medium_bitmap(), ssb.position_in_burst);
break;
case serving_cell_cfg_common_s::ssb_positions_in_burst_c_::types_opts::long_bitmap:
make_ssb_positions_in_burst(serv_cell_cfg.ssb_positions_in_burst.long_bitmap(), ssb.position_in_burst);
break;
case serving_cell_cfg_common_s::ssb_positions_in_burst_c_::types_opts::nulltype:
asn1::log_warning("SSB position in burst nulltype");
return false;
}
} else {
asn1::log_warning("SSB position in burst not present");
return false;
}
if (serv_cell_cfg.ssb_periodicity_serving_cell_present) {
ssb.periodicity_ms = (uint32_t)serv_cell_cfg.ssb_periodicity_serving_cell.to_number();
} else {
asn1::log_warning("SSB periodicity not present");
return false;
}
if (serv_cell_cfg.ssb_subcarrier_spacing_present) {
ssb.scs = make_subcarrier_spacing(serv_cell_cfg.ssb_subcarrier_spacing);
if (ssb.scs == srsran_subcarrier_spacing_invalid) {
return false;
}
} else {
asn1::log_warning("SSB subcarrier spacing not present");
return false;
}
if (out_ssb != nullptr) {
*out_ssb = ssb;
}
return true;
}
} // namespace srsran
namespace srsenb {

View File

@ -155,14 +155,19 @@ uint32_t srsran_min_symbol_sz_rb(uint32_t nof_prb)
float srsran_symbol_offset_s(uint32_t l, srsran_subcarrier_spacing_t scs)
{
// Compute at what symbol there is a longer CP
uint32_t cp_boundary = 7U << (uint32_t)scs;
uint32_t cp_boundary = SRSRAN_EXT_CP_SYMBOL(scs);
// First symbol CP
uint32_t N = 160;
uint32_t N = 0;
// Symbols in between the first and l
N += (2048 + 144) * l;
// Add extended CP samples from first OFDM symbol
if (l > 0) {
N += 16;
}
// Add extra samples at the longer CP boundary
if (l >= cp_boundary) {
N += 16;

View File

@ -76,6 +76,155 @@ void srsran_ssb_free(srsran_ssb_t* q)
SRSRAN_MEM_ZERO(q, srsran_ssb_t, 1);
}
static uint32_t ssb_first_symbol_caseA(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION])
{
// Case A - 15 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes of { 2 , 8 } + 14 ⋅ n . For
// carrier frequencies smaller than or equal to 3 GHz, n = 0 , 1 . For carrier frequencies within FR1 larger than 3
// GHz, n = 0 , 1 , 2 , 3 .
uint32_t count = 0;
uint32_t base_indexes[2] = {2, 8};
uint32_t N = 2;
if (cfg->center_freq_hz > 3e9) {
N = 4;
}
for (uint32_t n = 0; n < N; n++) {
for (uint32_t i = 0; i < 2; i++) {
indexes[count++] = base_indexes[i] + 14 * n;
}
}
return count;
}
static uint32_t ssb_first_symbol_caseB(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION])
{
// Case B - 30 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes { 4 , 8 , 16 , 20 } + 28 ⋅ n .
// For carrier frequencies smaller than or equal to 3 GHz, n = 0 . For carrier frequencies within FR1 larger than 3
// GHz, n = 0 , 1 .
uint32_t count = 0;
uint32_t base_indexes[4] = {4, 8, 16, 20};
uint32_t N = 1;
if (cfg->center_freq_hz > 3e9) {
N = 2;
}
for (uint32_t n = 0; n < N; n++) {
for (uint32_t i = 0; i < 4; i++) {
indexes[count++] = base_indexes[i] + 28 * n;
}
}
return count;
}
static uint32_t ssb_first_symbol_caseC(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION])
{
// Case C - 30 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes { 2 , 8 } +14 ⋅ n .
// - For paired spectrum operation
// - For carrier frequencies smaller than or equal to 3 GHz, n = 0 , 1 . For carrier frequencies within FR1 larger
// than 3 GHz, n = 0 , 1 , 2 , 3 .
// - For unpaired spectrum operation
// - For carrier frequencies smaller than or equal to 2.3 GHz, n = 0 , 1 . For carrier frequencies within FR1
// larger than 2.3 GHz, n = 0 , 1 , 2 , 3 .
uint32_t count = 0;
uint32_t base_indexes[2] = {2, 8};
uint32_t N = 4;
if ((cfg->duplex_mode == SRSRAN_DUPLEX_MODE_FDD && cfg->center_freq_hz <= 3e9) ||
(cfg->duplex_mode == SRSRAN_DUPLEX_MODE_TDD && cfg->center_freq_hz <= 2.3e9)) {
N = 2;
}
for (uint32_t n = 0; n < N; n++) {
for (uint32_t i = 0; i < 2; i++) {
indexes[count++] = base_indexes[i] + 14 * n;
}
}
return count;
}
static uint32_t ssb_first_symbol_caseD(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION])
{
// Case D - 120 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes { 4 , 8 , 16 , 20 } + 28 ⋅ n .
// For carrier frequencies within FR2, n = 0 , 1 , 2 , 3 , 5 , 6 , 7 , 8 , 10 , 11 , 12 , 13 , 15 , 16 , 17 , 18 .
uint32_t count = 0;
uint32_t base_indexes[4] = {4, 8, 16, 20};
uint32_t n_indexes[16] = {0, 1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18};
for (uint32_t j = 0; j < 16; j++) {
for (uint32_t i = 0; i < 4; i++) {
indexes[count++] = base_indexes[i] + 28 * n_indexes[j];
}
}
return count;
}
static uint32_t ssb_first_symbol_caseE(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION])
{
// Case E - 240 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes
//{ 8 , 12 , 16 , 20 , 32 , 36 , 40 , 44 } + 56 ⋅ n . For carrier frequencies within FR2, n = 0 , 1 , 2 , 3 , 5 , 6 ,
// 7 , 8 .
uint32_t count = 0;
uint32_t base_indexes[8] = {8, 12, 16, 20, 32, 38, 40, 44};
uint32_t n_indexes[8] = {0, 1, 2, 3, 5, 6, 7, 8};
for (uint32_t j = 0; j < 8; j++) {
for (uint32_t i = 0; i < 8; i++) {
indexes[count++] = base_indexes[i] + 56 * n_indexes[j];
}
}
return count;
}
static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i)
{
uint32_t indexes[SRSRAN_SSB_NOF_POSITION];
uint32_t Lmax = 0;
switch (cfg->pattern) {
case SRSRAN_SSB_PATTERN_A:
Lmax = ssb_first_symbol_caseA(cfg, indexes);
break;
case SRSRAN_SSB_PATTERN_B:
Lmax = ssb_first_symbol_caseB(cfg, indexes);
break;
case SRSRAN_SSB_PATTERN_C:
Lmax = ssb_first_symbol_caseC(cfg, indexes);
break;
case SRSRAN_SSB_PATTERN_D:
Lmax = ssb_first_symbol_caseD(cfg, indexes);
break;
case SRSRAN_SSB_PATTERN_E:
Lmax = ssb_first_symbol_caseE(cfg, indexes);
break;
case SRSRAN_SSB_PATTERN_INVALID:
ERROR("Invalid case");
return SRSRAN_ERROR;
}
uint32_t ssb_count = 0;
for (uint32_t i = 0; i < Lmax; i++) {
// There is a SSB transmission opportunity
if (cfg->position[i]) {
// Return the SSB transmission in burst
if (ssb_i == ssb_count) {
return (int)indexes[i];
}
ssb_count++;
}
}
return SRSRAN_ERROR;
}
int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg)
{
// Verify input parameters
@ -84,13 +233,38 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg)
}
// Calculate subcarrier spacing in Hz
q->scs_hz = (double)SRSRAN_SUBC_SPACING_NR(cfg->scs);
q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(cfg->scs);
// Get first symbol
int l_begin = ssb_first_symbol(cfg, 0);
if (l_begin < SRSRAN_SUCCESS) {
ERROR("Calculating first SSB symbol");
return SRSRAN_ERROR;
}
l_begin = 2;
float t_offset_s = srsran_symbol_offset_s((uint32_t)l_begin, cfg->scs);
if (isnan(t_offset_s) || isinf(t_offset_s) || t_offset_s < 0.0f) {
ERROR("Invalid first symbol (l_first=%d)", l_begin);
return SRSRAN_ERROR;
}
// Calculate SSB symbol size and integer offset
uint32_t symbol_sz = (uint32_t)round(cfg->srate_hz / q->scs_hz);
q->offset = (uint32_t)(cfg->freq_offset_hz / q->scs_hz);
q->cp0_sz = (160U * symbol_sz) / 2048U;
q->cp_sz = (144U * symbol_sz) / 2048U;
double freq_offset_hz = cfg->ssb_freq_hz - cfg->center_freq_hz;
uint32_t symbol_sz = (uint32_t)round(cfg->srate_hz / q->scs_hz);
q->f_offset = (int32_t)round(freq_offset_hz / q->scs_hz);
q->t_offset = (uint32_t)round(t_offset_s * cfg->srate_hz);
for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) {
uint32_t l_real = l + (uint32_t)l_begin;
uint32_t ref_cp_sz = 144U;
if (l_real == 0 || l_real == SRSRAN_EXT_CP_SYMBOL(cfg->scs)) {
ref_cp_sz = 160U;
}
q->cp_sz[l] = (ref_cp_sz * symbol_sz) / 2048U;
}
// Calculate SSB sampling error and check
double ssb_srate_error_Hz = ((double)symbol_sz * q->scs_hz) - cfg->srate_hz;
@ -100,9 +274,9 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg)
}
// Calculate SSB offset error and check
double ssb_offset_error_Hz = ((double)q->offset * q->scs_hz) - cfg->freq_offset_hz;
double ssb_offset_error_Hz = ((double)q->f_offset * q->scs_hz) - freq_offset_hz;
if (fabs(ssb_offset_error_Hz) > SSB_FREQ_OFFSET_MAX_ERROR_HZ) {
ERROR("SSB Offset error exceeds maximum allowed");
ERROR("SSB Offset (%.1f kHz) error exceeds maximum allowed", freq_offset_hz / 1e3);
return SRSRAN_ERROR;
}
@ -160,6 +334,22 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg)
return SRSRAN_SUCCESS;
}
bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx)
{
// Verify input
if (q == NULL) {
return false;
}
// Verify periodicity
if (q->cfg.periodicity_ms == 0) {
return false;
}
// Check periodicity
return (sf_idx % q->cfg.periodicity_ms == 0);
}
int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out)
{
// Verify input parameters
@ -198,24 +388,26 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m
srsran_vec_cf_zero(q->tmp_freq, q->symbol_sz);
// Modulate
const cf_t* in_ptr = in;
cf_t* out_ptr = out;
const cf_t* in_ptr = &in[q->t_offset];
cf_t* out_ptr = &out[q->t_offset];
for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) {
// Get CP length
uint32_t cp_len = (l == 0) ? q->cp0_sz : q->cp_sz;
uint32_t cp_len = q->cp_sz[l];
// Select symbol in grid
cf_t* ptr = &ssb_grid[l * SRSRAN_SSB_BW_SUBC];
// Map grid into frequency domain symbol
if (q->offset >= SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(&q->tmp_freq[q->offset - SRSRAN_SSB_BW_SUBC / 2], ptr, SRSRAN_SSB_BW_SUBC);
} else if (q->offset <= -SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(&q->tmp_freq[q->symbol_sz + q->offset - SRSRAN_SSB_BW_SUBC / 2], ptr, SRSRAN_SSB_BW_SUBC);
if (q->f_offset >= SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(&q->tmp_freq[q->f_offset - SRSRAN_SSB_BW_SUBC / 2], ptr, SRSRAN_SSB_BW_SUBC);
} else if (q->f_offset <= -SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(&q->tmp_freq[q->symbol_sz + q->f_offset - SRSRAN_SSB_BW_SUBC / 2], ptr, SRSRAN_SSB_BW_SUBC);
} else {
srsran_vec_cf_copy(&q->tmp_freq[0], &ptr[SRSRAN_SSB_BW_SUBC / 2 - q->offset], SRSRAN_SSB_BW_SUBC / 2 + q->offset);
srsran_vec_cf_copy(
&q->tmp_freq[q->symbol_sz - SRSRAN_SSB_BW_SUBC / 2 + q->offset], &ptr[0], SRSRAN_SSB_BW_SUBC / 2 - q->offset);
&q->tmp_freq[0], &ptr[SRSRAN_SSB_BW_SUBC / 2 - q->f_offset], SRSRAN_SSB_BW_SUBC / 2 + q->f_offset);
srsran_vec_cf_copy(&q->tmp_freq[q->symbol_sz - SRSRAN_SSB_BW_SUBC / 2 + q->f_offset],
&ptr[0],
SRSRAN_SSB_BW_SUBC / 2 - q->f_offset);
}
// Convert to time domain
@ -243,10 +435,10 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m
static int ssb_demodulate(srsran_ssb_t* q, const cf_t* in, cf_t ssb_grid[SRSRAN_SSB_NOF_RE])
{
const cf_t* in_ptr = in;
const cf_t* in_ptr = &in[q->t_offset];
for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) {
// Get CP length
uint32_t cp_len = (l == 0) ? q->cp0_sz : q->cp_sz;
uint32_t cp_len = q->cp_sz[l];
// Advance half CP, to avoid inter symbol interference
in_ptr += SRSRAN_FLOOR(cp_len, 2);
@ -265,14 +457,16 @@ static int ssb_demodulate(srsran_ssb_t* q, const cf_t* in, cf_t ssb_grid[SRSRAN_
cf_t* ptr = &ssb_grid[l * SRSRAN_SSB_BW_SUBC];
// Map frequency domain symbol into the SSB grid
if (q->offset >= SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(ptr, &q->tmp_freq[q->offset - SRSRAN_SSB_BW_SUBC / 2], SRSRAN_SSB_BW_SUBC);
} else if (q->offset <= -SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(ptr, &q->tmp_freq[q->symbol_sz + q->offset - SRSRAN_SSB_BW_SUBC / 2], SRSRAN_SSB_BW_SUBC);
if (q->f_offset >= SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(ptr, &q->tmp_freq[q->f_offset - SRSRAN_SSB_BW_SUBC / 2], SRSRAN_SSB_BW_SUBC);
} else if (q->f_offset <= -SRSRAN_SSB_BW_SUBC / 2) {
srsran_vec_cf_copy(ptr, &q->tmp_freq[q->symbol_sz + q->f_offset - SRSRAN_SSB_BW_SUBC / 2], SRSRAN_SSB_BW_SUBC);
} else {
srsran_vec_cf_copy(&ptr[SRSRAN_SSB_BW_SUBC / 2 - q->offset], &q->tmp_freq[0], SRSRAN_SSB_BW_SUBC / 2 + q->offset);
srsran_vec_cf_copy(
&ptr[0], &q->tmp_freq[q->symbol_sz - SRSRAN_SSB_BW_SUBC / 2 + q->offset], SRSRAN_SSB_BW_SUBC / 2 - q->offset);
&ptr[SRSRAN_SSB_BW_SUBC / 2 - q->f_offset], &q->tmp_freq[0], SRSRAN_SSB_BW_SUBC / 2 + q->f_offset);
srsran_vec_cf_copy(&ptr[0],
&q->tmp_freq[q->symbol_sz - SRSRAN_SSB_BW_SUBC / 2 + q->f_offset],
SRSRAN_SSB_BW_SUBC / 2 - q->f_offset);
}
// Normalize
@ -337,19 +531,26 @@ ssb_measure(srsran_ssb_t* q, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t N_
float cfo_hz = cargf(corr_pss * conjf(corr_sss)) / (2.0f * M_PI) * cfo_hz_max;
// Compute average RSRP
float rsrp = (SRSRAN_CSQABS(corr_pss) + SRSRAN_CSQABS(corr_sss)) / 2.0f;
float rsrp_pss = SRSRAN_CSQABS(corr_pss);
float rsrp_sss = SRSRAN_CSQABS(corr_sss);
float rsrp = (rsrp_pss + rsrp_sss) / 2.0f;
// Compute Noise
float n0 = 1e-9; // Almost 0
if (epre > rsrp) {
n0 = epre - rsrp;
float n0_pss = 1e-9; // Almost 0
float n0_sss = 1e-9; // Almost 0
if (epre_pss > rsrp_pss) {
n0_pss = epre - rsrp_pss;
}
if (epre_pss > rsrp_pss) {
n0_sss = epre - rsrp_sss;
}
float n0 = (n0_pss + n0_sss) / 2.0f;
// Put measurements together
meas->epre = epre;
meas->epre_dB = srsran_convert_power_to_dB(epre);
meas->rsrp = rsrp;
meas->epre_dB = srsran_convert_power_to_dB(rsrp);
meas->rsrp_dB = srsran_convert_power_to_dB(rsrp);
meas->n0 = n0;
meas->n0_dB = srsran_convert_power_to_dB(n0);
meas->snr_dB = meas->rsrp_dB - meas->n0_dB;

View File

@ -37,8 +37,8 @@ static cf_t* buffer = NULL; // Base-band buffer
#define RSRP_MAX_ERROR 1.0f
#define EPRE_MAX_ERROR 1.0f
#define N0_MAX_ERROR 2.0f
#define SNR_MAX_ERROR 2.0f
#define N0_MAX_ERROR 2.5f
#define SNR_MAX_ERROR 2.5f
#define CFO_MAX_ERROR (cfo_hz * 0.3f)
#define DELAY_MAX_ERROR (delay_us * 0.1f)
@ -90,12 +90,18 @@ static int assert_measure(const srsran_csi_trs_measurements_t* meas)
static int test_case_1(srsran_ssb_t* ssb)
{
uint64_t t_find_usec = 0;
uint64_t t_meas_usec = 0;
srsran_ssb_cfg_t ssb_cfg = {};
ssb_cfg.srate_hz = srate_hz;
ssb_cfg.freq_offset_hz = 0.0;
ssb_cfg.scs = ssb_scs;
// For benchmarking purposes
uint64_t t_find_usec = 0;
uint64_t t_meas_usec = 0;
// SSB configuration
srsran_ssb_cfg_t ssb_cfg = {};
ssb_cfg.srate_hz = srate_hz;
ssb_cfg.center_freq_hz = 3.5e9;
ssb_cfg.ssb_freq_hz = 3.5e9 - 960e3;
ssb_cfg.scs = ssb_scs;
ssb_cfg.pattern = SRSRAN_SSB_PATTERN_C;
ssb_cfg.position[0] = true; // Rest to false
TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS);
@ -123,6 +129,11 @@ static int test_case_1(srsran_ssb_t* ssb)
get_time_interval(t);
t_find_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL;
// Print measurement
char str[512];
srsran_csi_meas_info(&meas_search, str, sizeof(str));
INFO("test_case_1 - pci=%d %s", pci, str);
// Assert find and measurements
TESTASSERT(N_id_found == pci);
TESTASSERT(assert_measure(&meas_search) == SRSRAN_SUCCESS);
@ -135,11 +146,6 @@ static int test_case_1(srsran_ssb_t* ssb)
get_time_interval(t);
t_meas_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL;
// Print measurement
char str[512];
srsran_csi_meas_info(&meas, str, sizeof(str));
INFO("test_case_1 - pci=%d %s", pci, str);
// Assert measurements
TESTASSERT(assert_measure(&meas) == SRSRAN_SUCCESS);
}

View File

@ -50,6 +50,7 @@ private:
std::array<cf_t*, SRSRAN_MAX_PORTS> tx_buffer = {};
uint32_t buffer_sz = 0;
state* phy = nullptr;
srsran_ssb_t ssb = {};
srsran_ue_dl_nr_t ue_dl = {};
srsran_ue_ul_nr_t ue_ul = {};
srslog::basic_logger& logger;

View File

@ -11,6 +11,7 @@
*/
#include "srsue/hdr/phy/nr/cc_worker.h"
#include "srsran/common/band_helper.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/srsran.h"
@ -38,12 +39,20 @@ cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state* phy_sta
ERROR("Error initiating UE DL NR");
return;
}
srsran_ssb_args_t ssb_args = {};
ssb_args.enable_measure = true;
if (srsran_ssb_init(&ssb, &ssb_args) < SRSRAN_SUCCESS) {
ERROR("Error initiating SSB");
return;
}
}
cc_worker::~cc_worker()
{
srsran_ue_dl_nr_free(&ue_dl);
srsran_ue_ul_nr_free(&ue_ul);
srsran_ssb_free(&ssb);
for (cf_t* p : rx_buffer) {
if (p != nullptr) {
free(p);
@ -74,6 +83,29 @@ bool cc_worker::update_cfg()
return false;
}
double abs_freq_point_a_freq =
srsran::srsran_band_helper().nr_arfcn_to_freq(phy->cfg.carrier.absolute_frequency_point_a);
double abs_freq_ssb_freq = srsran::srsran_band_helper().nr_arfcn_to_freq(phy->cfg.carrier.absolute_frequency_ssb);
double carrier_center_freq = abs_freq_point_a_freq + (phy->cfg.carrier.nof_prb / 2 *
SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs) * SRSRAN_NRE);
uint16_t band = srsran::srsran_band_helper().get_band_from_dl_freq_Hz(carrier_center_freq);
srsran_ssb_cfg_t ssb_cfg = {};
ssb_cfg.srate_hz = srsran_min_symbol_sz_rb(phy->cfg.carrier.nof_prb) * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs);
ssb_cfg.center_freq_hz = carrier_center_freq;
ssb_cfg.ssb_freq_hz = abs_freq_ssb_freq;
ssb_cfg.scs = phy->cfg.ssb.scs;
ssb_cfg.pattern = srsran::srsran_band_helper().get_ssb_pattern(band, phy->cfg.ssb.scs);
memcpy(ssb_cfg.position, phy->cfg.ssb.position_in_burst.data(), sizeof(bool) * SRSRAN_SSB_NOF_POSITION);
ssb_cfg.duplex_mode = srsran::srsran_band_helper().get_duplex_mode(band);
ssb_cfg.periodicity_ms = phy->cfg.ssb.periodicity_ms;
if (srsran_ssb_set_cfg(&ssb, &ssb_cfg) < SRSRAN_SUCCESS) {
logger.error("Error setting SSB configuration");
return false;
}
configured = true;
return true;
@ -298,6 +330,37 @@ bool cc_worker::decode_pdsch_dl()
bool cc_worker::measure_csi()
{
// Measure SSB CSI
if (srsran_ssb_send(&ssb, dl_slot_cfg.idx)) {
srsran_csi_trs_measurements_t meas = {};
if (srsran_ssb_csi_measure(&ssb, phy->cfg.carrier.pci, rx_buffer[0], &meas) < SRSRAN_SUCCESS) {
logger.error("Error measuring SSB");
return false;
}
if (logger.debug.enabled()) {
std::array<char, 512> str = {};
srsran_csi_meas_info(&meas, str.data(), (uint32_t)str.size());
logger.debug("SSB-CSI: %s", str.data());
}
// Compute channel metrics and push it
ch_metrics_t ch_metrics = {};
ch_metrics.sinr = meas.snr_dB;
ch_metrics.rsrp = meas.rsrp_dB;
ch_metrics.rsrq = 0.0f; // Not supported
ch_metrics.rssi = 0.0f; // Not supported
ch_metrics.sync_err =
meas.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs));
phy->set_channel_metrics(ch_metrics);
// Compute synch metrics and report it to the PHY state
sync_metrics_t sync_metrics = {};
sync_metrics.cfo = meas.cfo_hz;
phy->set_sync_metrics(sync_metrics);
}
// Iterate all NZP-CSI-RS marked as TRS and perform channel measurements
for (uint32_t resource_set_id = 0; resource_set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS; resource_set_id++) {
// Select NZP-CSI-RS set
@ -321,10 +384,10 @@ bool cc_worker::measure_csi()
continue;
}
if (logger.info.enabled()) {
if (logger.debug.enabled()) {
std::array<char, 512> str = {};
srsran_csi_meas_info(&trs_measurements, str.data(), (uint32_t)str.size());
logger.info("NZP-CSI-RS (TRS): id=%d %s", resource_set_id, str.data());
logger.debug("NZP-CSI-RS (TRS): id=%d %s", resource_set_id, str.data());
}
// Compute channel metrics and push it
@ -376,11 +439,11 @@ bool cc_worker::measure_csi()
continue;
}
logger.info("NZP-CSI-RS: id=%d, rsrp=%+.1f epre=%+.1f snr=%+.1f",
resource_set_id,
measurements.wideband_rsrp_dBm,
measurements.wideband_epre_dBm,
measurements.wideband_snr_db);
logger.debug("NZP-CSI-RS: id=%d, rsrp=%+.1f epre=%+.1f snr=%+.1f",
resource_set_id,
measurements.wideband_rsrp_dBm,
measurements.wideband_epre_dBm,
measurements.wideband_snr_db);
// Report new measurement to the PHY state
phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id);
@ -416,7 +479,7 @@ bool cc_worker::work_dl()
return false;
}
// Measure CSI-RS
// Measure CSI
if (not measure_csi()) {
logger.error("Error measuring, aborting work DL");
return false;

View File

@ -1138,6 +1138,14 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg)
logger.warning("DL cfg common not present");
return false;
}
phy_cfg_nr_t::ssb_cfg_t ssb_cfg = {};
if (make_phy_ssb_cfg(recfg_with_sync.sp_cell_cfg_common, &ssb_cfg) == true) {
phy_cfg.ssb = ssb_cfg;
} else {
logger.warning("Warning while building ssb structure");
return false;
}
if (recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common_present) {
srsran_tdd_config_nr_t tdd;
if (make_phy_tdd_cfg(recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common, &tdd) == true) {