mirror of https://github.com/pvnis/srsRAN_4G.git
Initial NR PDSCH CSI-RS RE skip and other changes
parent
5bc55ec48c
commit
5bdf2c93b3
@ -0,0 +1,129 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_CSI_RS_CFG_H
|
||||
#define SRSRAN_CSI_RS_CFG_H
|
||||
|
||||
#include "srsran/config.h"
|
||||
#include "srsran/phy/common/phy_common_nr.h"
|
||||
|
||||
/**
|
||||
* @brief Maximum number of ZP CSI-RS resources per set defined in
|
||||
* - TS 38.214 clause 5.1.4.2 PDSCH resource mapping with RE level granularity
|
||||
* - TS 38.331 constant maxNrofZP-CSI-RS-ResourcesPerSet
|
||||
*/
|
||||
#define SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_PER_SET 16
|
||||
|
||||
/**
|
||||
* @brief Maximum number of ZP CSI-RS Sets defined in TS 38.331 constant maxNrofZP-CSI-RS-ResourceSets
|
||||
*/
|
||||
#define SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS 16
|
||||
|
||||
/**
|
||||
* @brief Maximum number of CSI-RS frequency domain allocation bits
|
||||
*/
|
||||
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_MAX 12
|
||||
|
||||
typedef enum SRSRAN_API {
|
||||
srsran_csi_rs_resource_mapping_row_1 = 0,
|
||||
srsran_csi_rs_resource_mapping_row_2,
|
||||
srsran_csi_rs_resource_mapping_row_4,
|
||||
srsran_csi_rs_resource_mapping_row_other,
|
||||
} srsran_csi_rs_resource_mapping_row_t;
|
||||
|
||||
typedef enum SRSRAN_API {
|
||||
srsran_csi_rs_resource_mapping_density_three = 0,
|
||||
srsran_csi_rs_resource_mapping_density_dot5_even,
|
||||
srsran_csi_rs_resource_mapping_density_dot5_odd,
|
||||
srsran_csi_rs_resource_mapping_density_one,
|
||||
srsran_csi_rs_resource_mapping_density_spare
|
||||
} srsran_csi_rs_density_t;
|
||||
|
||||
typedef enum SRSRAN_API {
|
||||
srsran_csi_rs_cdm_nocdm = 0,
|
||||
srsran_csi_rs_cdm_fd_cdm2,
|
||||
srsran_csi_rs_cdm_cdm4_fd2_td2,
|
||||
srsran_csi_rs_cdm_cdm8_fd2_td4
|
||||
} srsran_csi_rs_cdm_t;
|
||||
|
||||
/**
|
||||
* @brief Contains CSI-FrequencyOccupation flattened configuration
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
uint32_t start_rb; ///< PRB where this CSI resource starts in relation to common resource block #0 (CRB#0) on the
|
||||
///< common resource block grid. Only multiples of 4 are allowed (0, 4, ..., 274)
|
||||
|
||||
uint32_t nof_rb; ///< Number of PRBs across which this CSI resource spans. Only multiples of 4 are allowed. The
|
||||
///< smallest configurable number is the minimum of 24 and the width of the associated BWP. If the
|
||||
///< configured value is larger than the width of the corresponding BWP, the UE shall assume that the
|
||||
///< actual CSI-RS bandwidth is equal to the width of the BWP.
|
||||
} srsran_csi_rs_freq_occupation_t;
|
||||
|
||||
/**
|
||||
* @brief Contains CSI-ResourcePeriodicityAndOffset flattened configuration
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
uint32_t period; // 4,5,8,10,16,20,32,40,64,80,160,320,640
|
||||
uint32_t offset; // 0..period-1
|
||||
} srsran_csi_rs_period_and_offset_t;
|
||||
|
||||
/**
|
||||
* @brief Contains CSI-RS-ResourceMapping flattened configuration
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
srsran_csi_rs_resource_mapping_row_t row;
|
||||
bool frequency_domain_alloc[SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_MAX];
|
||||
uint32_t nof_ports; // 1, 2, 4, 8, 12, 16, 24, 32
|
||||
uint32_t first_symbol_idx; // 0..13
|
||||
uint32_t first_symbol_idx2; // 2..12 (set to 0 for disabled)
|
||||
srsran_csi_rs_cdm_t cdm;
|
||||
srsran_csi_rs_density_t density;
|
||||
srsran_csi_rs_freq_occupation_t freq_band;
|
||||
} srsran_csi_rs_resource_mapping_t;
|
||||
|
||||
/**
|
||||
* @brief Contains TS 38.331 NZP-CSI-RS-Resource flattened configuration
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping
|
||||
float power_control_offset; ///< -8..15 dB
|
||||
float power_control_offset_ss; ///< -3, 0, 3, 6 dB
|
||||
uint32_t scrambling_id; ///< 0..1023
|
||||
srsran_csi_rs_period_and_offset_t periodicity; ///< Periodicity
|
||||
} srsran_csi_rs_nzp_resource_t;
|
||||
|
||||
/**
|
||||
* @brief Non-Zero-Power CSI resource set
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
srsran_csi_rs_nzp_resource_t data[SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_PER_SET]; ///< Resources
|
||||
uint32_t count; ///< Set to zero for not present
|
||||
bool trs_info; ///< Indicates that the antenna port for all NZP-CSI-RS resources in the CSI-RS resource set is same.
|
||||
} srsran_csi_rs_nzp_set_t;
|
||||
|
||||
/**
|
||||
* @brief Contains TS 38.331 ZP-CSI-RS-Resource flattened configuration
|
||||
*/
|
||||
typedef struct {
|
||||
srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping
|
||||
srsran_csi_rs_period_and_offset_t periodicity;
|
||||
} srsran_csi_rs_zp_resource_t;
|
||||
|
||||
/**
|
||||
* @brief Zero-Power CSI resource set
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
srsran_csi_rs_zp_resource_t data[SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_PER_SET]; ///< Resources
|
||||
uint32_t count; ///< Number of resources in the set
|
||||
} srsran_csi_rs_zp_set_t;
|
||||
|
||||
#endif // SRSRAN_CSI_RS_CFG_H
|
@ -0,0 +1,123 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_RE_PATTERN_H
|
||||
#define SRSRAN_RE_PATTERN_H
|
||||
|
||||
#include "../common/phy_common_nr.h"
|
||||
|
||||
/**
|
||||
* @brief Maximum number of elements in a pattern list
|
||||
*/
|
||||
#define SRSRAN_RE_PATTERN_LIST_SIZE 4
|
||||
|
||||
/**
|
||||
* @brief Characterizes a pattern in frequency-time domain in an NR slot resource grid
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
uint32_t rb_begin; ///< RB where the pattern begins in frequency domain
|
||||
uint32_t rb_end; ///< RB where the pattern ends in frequency domain (excluded)
|
||||
uint32_t rb_stride; ///< RB index jump
|
||||
bool sc[SRSRAN_NRE]; ///< Frequency-domain pattern
|
||||
bool symbol[SRSRAN_NSYMB_PER_SLOT_NR]; ///< Indicates OFDM symbols where the pattern is present
|
||||
} srsran_re_pattern_t;
|
||||
|
||||
/**
|
||||
* @brief List of RE patterns
|
||||
*/
|
||||
typedef struct SRSRAN_API {
|
||||
srsran_re_pattern_t data[SRSRAN_RE_PATTERN_LIST_SIZE]; ///< Actual patterns
|
||||
uint32_t count; ///< Number of RE patterns
|
||||
} srsran_re_pattern_list_t;
|
||||
|
||||
/**
|
||||
* @brief Calculates if a pattern matches a RE given a symbol l and a subcarrier k
|
||||
* @param list Provides a list of patterns
|
||||
* @param l OFDM symbol index
|
||||
* @param k Subcarrier index
|
||||
* @return True if pattern is valid and there is a match, false otherwise
|
||||
*/
|
||||
SRSRAN_API bool srsran_re_pattern_to_mask(const srsran_re_pattern_list_t* list, uint32_t l, uint32_t k);
|
||||
|
||||
/**
|
||||
* @brief Calculates the pattern mask for an entire symbol from a RE pattern list
|
||||
* @param list Provides a list of patterns
|
||||
* @param l OFDM symbol index
|
||||
* @param[out] mask Mask vector
|
||||
* @return SRSRAN_SUCCESS if the mask is computed successfully, SRSRAN_ERROR code otherwise
|
||||
*/
|
||||
SRSRAN_API int srsran_re_pattern_to_symbol_mask(const srsran_re_pattern_t* pattern, uint32_t l, bool* mask);
|
||||
|
||||
/**
|
||||
* @brief Calculates the pattern mask for an entire symbol from a RE pattern
|
||||
* @param list Provides a list of patterns
|
||||
* @param l OFDM symbol index
|
||||
* @param[out] mask Mask vector
|
||||
* @return SRSRAN_SUCCESS if the mask is computed successfully, SRSRAN_ERROR code otherwise
|
||||
*/
|
||||
SRSRAN_API int srsran_re_pattern_list_to_symbol_mask(const srsran_re_pattern_list_t* list, uint32_t l, bool* mask);
|
||||
|
||||
/**
|
||||
* @brief Merges a pattern into the pattern list, it either merges subcarrier or symbol mask or simply appends a new
|
||||
* pattern
|
||||
* @param patterns Provides a list of patterns
|
||||
* @param p Provides pattern to merge
|
||||
* @return SRSRAN_SUCCESS if merging is successful, SRSRAN_ERROR code otherwise
|
||||
*/
|
||||
SRSRAN_API int srsran_re_pattern_merge(srsran_re_pattern_list_t* list, const srsran_re_pattern_t* p);
|
||||
|
||||
/**
|
||||
* @brief Checks collision between a RE pattern list and a RE pattern
|
||||
* @param list Provides pattern list
|
||||
* @param p Provides a pattern
|
||||
* @return SRSLTE_SUCCESS if no collision is detected, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
SRSRAN_API int srsran_re_pattern_check_collision(const srsran_re_pattern_list_t* list, const srsran_re_pattern_t* p);
|
||||
|
||||
/**
|
||||
* @brief Initialises a given pattern list
|
||||
* @param patterns Provides a list of patterns
|
||||
*/
|
||||
SRSRAN_API void srsran_re_pattern_reset(srsran_re_pattern_list_t* list);
|
||||
|
||||
/**
|
||||
* @brief Writes a RE pattern information into a string
|
||||
* @param pattern Provides the pattern
|
||||
* @param str Provides string pointer
|
||||
* @param str_len Maximum string length
|
||||
* @return The number of characters writen into the string
|
||||
*/
|
||||
SRSRAN_API uint32_t srsran_re_pattern_info(const srsran_re_pattern_t* pattern, char* str, uint32_t str_len);
|
||||
|
||||
/**
|
||||
* @brief Writes a RE pattern list information into a string
|
||||
* @param pattern Provides the pattern list
|
||||
* @param str Provides string pointer
|
||||
* @param str_len Maximum string length
|
||||
* @return The number of characters writen into the string
|
||||
*/
|
||||
SRSRAN_API uint32_t srsran_re_pattern_list_info(const srsran_re_pattern_list_t* pattern, char* str, uint32_t str_len);
|
||||
|
||||
/**
|
||||
* @brief Counts the number of RE in a transmission characterised by initial and final symbol indexes and a PRB mask.
|
||||
* @param list RE pattern list
|
||||
* @param symbol_begin First transmission symbol
|
||||
* @param symbol_end Last (excluded) transmission symbol
|
||||
* @param prb_mask Frequency domain resource block mask
|
||||
* @return The number of RE occupied by the pattern list in the transmission
|
||||
*/
|
||||
SRSRAN_API uint32_t srsran_re_pattern_list_count(const srsran_re_pattern_list_t* list,
|
||||
uint32_t symbol_begin,
|
||||
uint32_t symbol_end,
|
||||
const bool prb_mask[SRSRAN_MAX_PRB_NR]);
|
||||
|
||||
#endif // SRSRAN_RE_PATTERN_H
|
@ -0,0 +1,229 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsran/common/test_common.h"
|
||||
#include "srsran/phy/ch_estimation/csi_rs.h"
|
||||
|
||||
static srsran_carrier_nr_t carrier = {};
|
||||
|
||||
static int test_row1()
|
||||
{
|
||||
for (uint32_t k = 0; k < SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1; k++) {
|
||||
// Create CSI-RS mapping
|
||||
srsran_csi_rs_resource_mapping_t m; // Dont initialise for detecting not initialised memory
|
||||
m.row = srsran_csi_rs_resource_mapping_row_1;
|
||||
for (uint32_t j = 0; j < SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1; j++) {
|
||||
m.frequency_domain_alloc[j] = (k == j);
|
||||
}
|
||||
m.nof_ports = 1;
|
||||
m.first_symbol_idx = 0;
|
||||
m.cdm = srsran_csi_rs_cdm_nocdm;
|
||||
m.density = srsran_csi_rs_resource_mapping_density_three;
|
||||
m.freq_band.start_rb = carrier.start;
|
||||
m.freq_band.nof_rb = carrier.nof_prb;
|
||||
|
||||
// Create Pattern list and initialise
|
||||
srsran_re_pattern_list_t patterns;
|
||||
srsran_re_pattern_reset(&patterns);
|
||||
|
||||
// Generate pattern list from CSI-RS mapping
|
||||
TESTASSERT(srsran_csi_rs_append_resource_to_pattern(&carrier, &m, &patterns) == SRSRAN_SUCCESS);
|
||||
|
||||
// Assert generated pattern
|
||||
TESTASSERT(patterns.count == 1);
|
||||
TESTASSERT(patterns.data[0].rb_begin == m.freq_band.start_rb);
|
||||
TESTASSERT(patterns.data[0].rb_end == m.freq_band.start_rb + m.freq_band.nof_rb);
|
||||
TESTASSERT(patterns.data[0].rb_stride == 1);
|
||||
for (uint32_t j = 0; j < SRSRAN_NRE; j++) {
|
||||
TESTASSERT(patterns.data[0].sc[j] ==
|
||||
(j % SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1 == (SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1 - 1 - k)));
|
||||
}
|
||||
for (uint32_t j = 0; j < SRSRAN_NSYMB_PER_SLOT_NR; j++) {
|
||||
TESTASSERT(patterns.data[0].symbol[j] == (j == m.first_symbol_idx));
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_row2()
|
||||
{
|
||||
for (srsran_csi_rs_density_t density = srsran_csi_rs_resource_mapping_density_dot5_even;
|
||||
density <= srsran_csi_rs_resource_mapping_density_one;
|
||||
density++) {
|
||||
for (uint32_t k = 0; k < SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW2; k++) {
|
||||
// Create CSI-RS mapping
|
||||
srsran_csi_rs_resource_mapping_t m; // Dont initialise for detecting not initialised memory
|
||||
m.row = srsran_csi_rs_resource_mapping_row_2;
|
||||
for (uint32_t j = 0; j < SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW2; j++) {
|
||||
m.frequency_domain_alloc[j] = (k == j);
|
||||
}
|
||||
m.nof_ports = 1;
|
||||
m.first_symbol_idx = 0;
|
||||
m.cdm = srsran_csi_rs_cdm_nocdm;
|
||||
m.density = density;
|
||||
m.freq_band.start_rb = carrier.start;
|
||||
m.freq_band.nof_rb = carrier.nof_prb;
|
||||
|
||||
// Create Pattern list and initialise
|
||||
srsran_re_pattern_list_t patterns;
|
||||
srsran_re_pattern_reset(&patterns);
|
||||
|
||||
// Generate pattern list from CSI-RS mapping
|
||||
TESTASSERT(srsran_csi_rs_append_resource_to_pattern(&carrier, &m, &patterns) == SRSRAN_SUCCESS);
|
||||
|
||||
// Assert generated pattern
|
||||
uint32_t rb_stride = (density == srsran_csi_rs_resource_mapping_density_one) ? 1 : 2;
|
||||
uint32_t rb_start = carrier.start;
|
||||
if ((rb_start % 2 == 0 && density == srsran_csi_rs_resource_mapping_density_dot5_odd) ||
|
||||
(rb_start % 2 == 1 && density == srsran_csi_rs_resource_mapping_density_dot5_even)) {
|
||||
rb_start++;
|
||||
}
|
||||
TESTASSERT(patterns.count == 1);
|
||||
TESTASSERT(patterns.data[0].rb_begin == rb_start);
|
||||
TESTASSERT(patterns.data[0].rb_end == m.freq_band.start_rb + m.freq_band.nof_rb);
|
||||
TESTASSERT(patterns.data[0].rb_stride == rb_stride);
|
||||
for (uint32_t j = 0; j < SRSRAN_NRE; j++) {
|
||||
TESTASSERT(patterns.data[0].sc[j] == (j == (SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW2 - 1 - k)));
|
||||
}
|
||||
for (uint32_t j = 0; j < SRSRAN_NSYMB_PER_SLOT_NR; j++) {
|
||||
TESTASSERT(patterns.data[0].symbol[j] == (j == m.first_symbol_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_row4()
|
||||
{
|
||||
for (uint32_t k = 0; k < SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW4; k++) {
|
||||
// Create CSI-RS mapping
|
||||
srsran_csi_rs_resource_mapping_t m; // Dont initialise for detecting not initialised memory
|
||||
m.row = srsran_csi_rs_resource_mapping_row_4;
|
||||
for (uint32_t j = 0; j < SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW4; j++) {
|
||||
m.frequency_domain_alloc[j] = (k == j);
|
||||
}
|
||||
m.nof_ports = 4;
|
||||
m.first_symbol_idx = 0;
|
||||
m.cdm = srsran_csi_rs_cdm_fd_cdm2;
|
||||
m.density = srsran_csi_rs_resource_mapping_density_one;
|
||||
m.freq_band.start_rb = carrier.start;
|
||||
m.freq_band.nof_rb = carrier.nof_prb;
|
||||
|
||||
// Create Pattern list and initialise
|
||||
srsran_re_pattern_list_t patterns;
|
||||
srsran_re_pattern_reset(&patterns);
|
||||
|
||||
// Generate pattern list from CSI-RS mapping
|
||||
TESTASSERT(srsran_csi_rs_append_resource_to_pattern(&carrier, &m, &patterns) == SRSRAN_SUCCESS);
|
||||
|
||||
// Assert generated pattern
|
||||
TESTASSERT(patterns.count == 1);
|
||||
TESTASSERT(patterns.data[0].rb_begin == m.freq_band.start_rb);
|
||||
TESTASSERT(patterns.data[0].rb_end == m.freq_band.start_rb + m.freq_band.nof_rb);
|
||||
TESTASSERT(patterns.data[0].rb_stride == 1);
|
||||
for (uint32_t j = 0; j < SRSRAN_NRE; j++) {
|
||||
uint32_t k_begin = (SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW4 - 1 - k) * 4;
|
||||
uint32_t k_end = k_begin + 4;
|
||||
TESTASSERT(patterns.data[0].sc[j] == (j >= k_begin && j < k_end));
|
||||
}
|
||||
for (uint32_t j = 0; j < SRSRAN_NSYMB_PER_SLOT_NR; j++) {
|
||||
TESTASSERT(patterns.data[0].symbol[j] == (j == m.first_symbol_idx));
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_mix()
|
||||
{
|
||||
srsran_csi_rs_resource_mapping_t resource0 = {};
|
||||
resource0.row = srsran_csi_rs_resource_mapping_row_4;
|
||||
resource0.frequency_domain_alloc[0] = true;
|
||||
resource0.frequency_domain_alloc[1] = false;
|
||||
resource0.frequency_domain_alloc[2] = false;
|
||||
resource0.nof_ports = 4;
|
||||
resource0.first_symbol_idx = 8;
|
||||
resource0.cdm = srsran_csi_rs_cdm_fd_cdm2;
|
||||
resource0.density = srsran_csi_rs_resource_mapping_density_one;
|
||||
resource0.freq_band.start_rb = 0;
|
||||
resource0.freq_band.nof_rb = 52;
|
||||
|
||||
srsran_csi_rs_resource_mapping_t resource1 = {};
|
||||
resource1.row = srsran_csi_rs_resource_mapping_row_2;
|
||||
resource1.frequency_domain_alloc[0] = true;
|
||||
resource1.frequency_domain_alloc[1] = false;
|
||||
resource1.frequency_domain_alloc[2] = false;
|
||||
resource1.frequency_domain_alloc[3] = false;
|
||||
resource1.frequency_domain_alloc[4] = false;
|
||||
resource1.frequency_domain_alloc[5] = false;
|
||||
resource1.frequency_domain_alloc[6] = false;
|
||||
resource1.frequency_domain_alloc[7] = false;
|
||||
resource1.frequency_domain_alloc[8] = false;
|
||||
resource1.frequency_domain_alloc[9] = false;
|
||||
resource1.frequency_domain_alloc[10] = false;
|
||||
resource1.frequency_domain_alloc[11] = false;
|
||||
resource1.nof_ports = 1;
|
||||
resource1.first_symbol_idx = 4;
|
||||
resource1.cdm = srsran_csi_rs_cdm_nocdm;
|
||||
resource1.density = srsran_csi_rs_resource_mapping_density_one;
|
||||
resource1.freq_band.start_rb = 0;
|
||||
resource1.freq_band.nof_rb = 52;
|
||||
|
||||
// Initialise pattern list
|
||||
srsran_re_pattern_list_t patterns;
|
||||
srsran_re_pattern_reset(&patterns);
|
||||
|
||||
// Generate pattern list from CSI-RS mapping
|
||||
TESTASSERT(srsran_csi_rs_append_resource_to_pattern(&carrier, &resource0, &patterns) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(srsran_csi_rs_append_resource_to_pattern(&carrier, &resource1, &patterns) == SRSRAN_SUCCESS);
|
||||
|
||||
// Assert generated pattern
|
||||
TESTASSERT(patterns.count == 2);
|
||||
|
||||
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
|
||||
bool mask[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {};
|
||||
|
||||
TESTASSERT(srsran_re_pattern_list_to_symbol_mask(&patterns, l, mask) == SRSRAN_SUCCESS);
|
||||
|
||||
if (l == resource0.first_symbol_idx) {
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE * SRSRAN_MAX_PRB_NR; k++) {
|
||||
TESTASSERT(mask[k] == ((k < 52 * SRSRAN_NRE) && (k % SRSRAN_NRE >= 8)));
|
||||
}
|
||||
} else if (l == resource1.first_symbol_idx) {
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE * SRSRAN_MAX_PRB_NR; k++) {
|
||||
TESTASSERT(mask[k] == ((k < 52 * SRSRAN_NRE) && (k % SRSRAN_NRE == 11)));
|
||||
}
|
||||
} else {
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE * SRSRAN_MAX_PRB_NR; k++) {
|
||||
TESTASSERT(mask[k] == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Initialise carrier
|
||||
carrier.start = 0;
|
||||
carrier.nof_prb = 52;
|
||||
|
||||
TESTASSERT(test_row1() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_row2() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_row4() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_mix() == SRSRAN_SUCCESS);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
@ -0,0 +1,320 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsran/phy/utils/re_pattern.h"
|
||||
#include "srsran/phy/utils/debug.h"
|
||||
#include "srsran/phy/utils/vector.h"
|
||||
|
||||
bool srsran_re_pattern_to_mask(const srsran_re_pattern_list_t* list, uint32_t l, uint32_t k)
|
||||
{
|
||||
uint32_t rb_idx = k % SRSRAN_NRE;
|
||||
uint32_t sc_idx = k / SRSRAN_NRE;
|
||||
|
||||
// Check pattern list is valid
|
||||
if (list == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate all given patterns
|
||||
for (uint32_t i = 0; i < list->count; i++) {
|
||||
const srsran_re_pattern_t* pattern = &list->data[i];
|
||||
|
||||
// Skip pattern if it is not active in this OFDM symbol
|
||||
if (!pattern->symbol[l]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip pattern if RB index is put of the pattern bounds
|
||||
if (rb_idx < pattern->rb_begin || rb_idx >= pattern->rb_end) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Matched SC, early return
|
||||
if (pattern->sc[sc_idx]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If reached here, no pattern was matched
|
||||
return false;
|
||||
}
|
||||
|
||||
int srsran_re_pattern_to_symbol_mask(const srsran_re_pattern_t* pattern, uint32_t l, bool* mask)
|
||||
{
|
||||
// Check inputs
|
||||
if (pattern == NULL || mask == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Check symbol index is in range
|
||||
if (l >= SRSRAN_NSYMB_PER_SLOT_NR) {
|
||||
ERROR("Symbol index is out of range");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Skip pattern if it is not active in this OFDM symbol
|
||||
if (!pattern->symbol[l]) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Make sure RB end is bounded
|
||||
if (pattern->rb_end > SRSRAN_MAX_PRB_NR) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Add mask for pattern
|
||||
for (uint32_t rb_idx = pattern->rb_begin; rb_idx < pattern->rb_end; rb_idx += pattern->rb_stride) {
|
||||
for (uint32_t sc_idx = 0; sc_idx < SRSRAN_NRE; sc_idx++) {
|
||||
mask[rb_idx * SRSRAN_NRE + sc_idx] |= pattern->sc[sc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_re_pattern_list_to_symbol_mask(const srsran_re_pattern_list_t* list, uint32_t l, bool* mask)
|
||||
{
|
||||
// Check inputs
|
||||
if (list == NULL || mask == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Iterate all given patterns
|
||||
for (uint32_t i = 0; i < list->count; i++) {
|
||||
if (srsran_re_pattern_to_symbol_mask(&list->data[i], l, mask) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error calculating mask");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_re_pattern_merge(srsran_re_pattern_list_t* list, const srsran_re_pattern_t* p)
|
||||
{
|
||||
// Check inputs are valid
|
||||
if (list == NULL || p == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Count number of subcarrier mask
|
||||
uint32_t kcount = 0;
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE; k++) {
|
||||
kcount += p->sc[k] ? 1 : 0;
|
||||
}
|
||||
|
||||
// Count number of symbol mask
|
||||
uint32_t lcount = 0;
|
||||
for (uint32_t l = 0; l < SRSRAN_NRE; l++) {
|
||||
lcount += p->symbol[l] ? 1 : 0;
|
||||
}
|
||||
|
||||
// If any mask is empty, ignore
|
||||
if (kcount == 0 || lcount == 0) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Iterate all given patterns
|
||||
for (uint32_t i = 0; i < list->count; i++) {
|
||||
srsran_re_pattern_t* pattern = &list->data[i];
|
||||
|
||||
// Skip if RB parameters dont match
|
||||
if (pattern->rb_begin != p->rb_begin || pattern->rb_end != p->rb_end || pattern->rb_stride != p->rb_stride) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if symbol mask matches
|
||||
bool lmatch = (memcmp(pattern->symbol, p->symbol, SRSRAN_NSYMB_PER_SLOT_NR) == 0);
|
||||
|
||||
// Check if sc mask matches
|
||||
bool kmatch = (memcmp(pattern->sc, p->sc, SRSRAN_NRE) == 0);
|
||||
|
||||
// If OFDM symbols and subcarriers mask match, it means that the patterns are completely overlapped and no merging
|
||||
// is required
|
||||
if (kmatch && lmatch) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// If OFDM symbols mask matches, merge subcarrier mask
|
||||
if (lmatch) {
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE; k++) {
|
||||
pattern->sc[k] |= p->sc[k];
|
||||
}
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// If subcarriers mask matches, merge OFDM symbols mask
|
||||
if (kmatch) {
|
||||
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
|
||||
pattern->symbol[l] |= p->symbol[l];
|
||||
}
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// If reached here, no pattern was matched. Try appending
|
||||
if (list->count >= SRSRAN_RE_PATTERN_LIST_SIZE) {
|
||||
ERROR("Insufficient number of available RE patterns in list");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Append
|
||||
list->data[list->count] = *p;
|
||||
list->count++;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_re_pattern_check_collision(const srsran_re_pattern_list_t* list, const srsran_re_pattern_t* p)
|
||||
{
|
||||
// Check inputs are valid
|
||||
if (list == NULL || p == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Count number of subcarrier mask
|
||||
uint32_t kcount = 0;
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE; k++) {
|
||||
kcount += p->sc[k] ? 1 : 0;
|
||||
}
|
||||
|
||||
// Count number of symbol mask
|
||||
uint32_t lcount = 0;
|
||||
for (uint32_t l = 0; l < SRSRAN_NRE; l++) {
|
||||
lcount += p->symbol[l] ? 1 : 0;
|
||||
}
|
||||
|
||||
// If any mask is empty, no collision
|
||||
if (kcount == 0 || lcount == 0) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Iterate all given patterns
|
||||
for (uint32_t i = 0; i < list->count; i++) {
|
||||
const srsran_re_pattern_t* pattern = &list->data[i];
|
||||
|
||||
// Skip if RB do not overlap
|
||||
if (pattern->rb_begin > p->rb_end || p->rb_begin > pattern->rb_end) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if symbol are matched
|
||||
bool lmatch = false;
|
||||
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR && !lmatch; l++) {
|
||||
// Consider match if both patterns have a positive symbol in common
|
||||
lmatch = (p->symbol[l] && pattern->symbol[l]);
|
||||
}
|
||||
|
||||
// If the symbols are not matched, skip pattern
|
||||
if (!lmatch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if any subcarrier mask matches
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE; k++) {
|
||||
// Consider a collision if both subcarrier mask are true
|
||||
if (p->sc[k] && pattern->sc[k]) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If reached here, means no collision
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
void srsran_re_pattern_reset(srsran_re_pattern_list_t* list)
|
||||
{
|
||||
if (list == NULL) {
|
||||
return;
|
||||
}
|
||||
SRSRAN_MEM_ZERO(list, srsran_re_pattern_list_t, 1);
|
||||
}
|
||||
|
||||
uint32_t srsran_re_pattern_info(const srsran_re_pattern_t* pattern, char* str, uint32_t str_len)
|
||||
{
|
||||
if (pattern == NULL || str == NULL || str_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char subc[SRSRAN_NRE + 1] = {};
|
||||
srsran_vec_sprint_bin(subc, SRSRAN_NRE + 1, (uint8_t*)pattern->sc, SRSRAN_NRE);
|
||||
|
||||
char symb[SRSRAN_NSYMB_PER_SLOT_NR + 1] = {};
|
||||
srsran_vec_sprint_bin(symb, SRSRAN_NSYMB_PER_SLOT_NR + 1, (uint8_t*)pattern->symbol, SRSRAN_NSYMB_PER_SLOT_NR);
|
||||
|
||||
return srsran_print_check(str,
|
||||
str_len,
|
||||
0,
|
||||
"begin=%d end=%d stride=%d sc=%s symb=%s ",
|
||||
pattern->rb_begin,
|
||||
pattern->rb_end,
|
||||
pattern->rb_stride,
|
||||
subc,
|
||||
symb);
|
||||
}
|
||||
|
||||
uint32_t srsran_re_pattern_list_info(const srsran_re_pattern_list_t* list, char* str, uint32_t str_len)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
if (list == NULL || str == NULL || str_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < list->count; i++) {
|
||||
len = srsran_print_check(str, str_len, len, "RE%d: ", i);
|
||||
len += srsran_re_pattern_info(&list->data[i], &str[len], str_len - len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint32_t srsran_re_pattern_list_count(const srsran_re_pattern_list_t* list,
|
||||
uint32_t symbol_begin,
|
||||
uint32_t symbol_end,
|
||||
const bool prb_mask[SRSRAN_MAX_PRB_NR])
|
||||
{
|
||||
uint32_t count = 0;
|
||||
if (list == NULL || prb_mask == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Iterate over all symbols and create a symbol mask
|
||||
for (uint32_t l = symbol_begin; l < symbol_end; l++) {
|
||||
// Entire symbol mask to prevent overlapped RE to count twice
|
||||
bool symbol_mask[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {};
|
||||
|
||||
// For each pattern, compute symbol mask
|
||||
for (uint32_t i = 0; i < list->count; i++) {
|
||||
if (srsran_re_pattern_to_symbol_mask(&list->data[i], l, symbol_mask) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error calculating symbol mask");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Count number of masked elements
|
||||
for (uint32_t rb = 0; rb < SRSRAN_MAX_PRB_NR; rb++) {
|
||||
// Skip PRB if disabled
|
||||
if (!prb_mask[rb]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterate all subcarriers in the PRB
|
||||
for (uint32_t k = rb * SRSRAN_NRE; k < (rb + 1) * SRSRAN_NRE; k++) {
|
||||
// Count only the true masked RE
|
||||
count += (uint32_t)symbol_mask[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsran/common/test_common.h"
|
||||
#include "srsran/phy/utils/re_pattern.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
srsran_re_pattern_list_t pattern_list;
|
||||
|
||||
// Reset list
|
||||
srsran_re_pattern_reset(&pattern_list);
|
||||
|
||||
// Create first pattern and merge
|
||||
srsran_re_pattern_t pattern_1 = {};
|
||||
pattern_1.rb_begin = 1;
|
||||
pattern_1.rb_end = 50;
|
||||
pattern_1.rb_stride = 1;
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE; k++) {
|
||||
pattern_1.sc[k] = (k % 2 == 0); // Only even subcarriers
|
||||
}
|
||||
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
|
||||
pattern_1.symbol[l] = (l % 2 == 0); // Only even symbols
|
||||
}
|
||||
TESTASSERT(srsran_re_pattern_merge(&pattern_list, &pattern_1) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pattern_list.count == 1);
|
||||
|
||||
// Create second pattern and merge
|
||||
srsran_re_pattern_t pattern_2 = pattern_1;
|
||||
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
|
||||
pattern_2.symbol[l] = (l % 2 == 1); // Only odd symbols
|
||||
}
|
||||
TESTASSERT(srsran_re_pattern_merge(&pattern_list, &pattern_2) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pattern_list.count == 1);
|
||||
|
||||
// Assert generated mask
|
||||
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
|
||||
bool mask[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {};
|
||||
TESTASSERT(srsran_re_pattern_list_to_symbol_mask(&pattern_list, l, mask) == SRSRAN_SUCCESS);
|
||||
for (uint32_t k = 0; k < SRSRAN_NRE * SRSRAN_MAX_PRB_NR; k++) {
|
||||
if (k >= pattern_1.rb_begin * SRSRAN_NRE && k < pattern_1.rb_end * SRSRAN_NRE &&
|
||||
(k / SRSRAN_NRE - pattern_1.rb_begin) % pattern_1.rb_stride == 0) {
|
||||
TESTASSERT(mask[k] == (k % 2 == 0));
|
||||
} else {
|
||||
TESTASSERT(mask[k] == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue