Initial NR PDSCH CSI-RS RE skip and other changes

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 5bc55ec48c
commit 5bdf2c93b3

@ -161,6 +161,63 @@ struct phy_cfg_nr_t {
pdcch.search_space[2].nof_candidates[4] = 0;
pdcch.search_space[2].type = srsran_search_space_type_ue;
pdcch.search_space_present[2] = true;
// pdsch-Config: setup (1)
// setup
// dmrs-DownlinkForPDSCH-MappingTypeA: setup (1)
// setup
// dmrs-AdditionalPosition: pos1 (1)
// tci-StatesToAddModList: 1 item
// Item 0
// TCI-State
// tci-StateId: 0
// qcl-Type1
// referenceSignal: ssb (1)
// ssb: 0
// qcl-Type: typeD (3)
// resourceAllocation: resourceAllocationType1 (1)
// rbg-Size: config1 (0)
// prb-BundlingType: staticBundling (0)
// staticBundling
// bundleSize: wideband (1)
// zp-CSI-RS-ResourceToAddModList: 1 item
// Item 0
// ZP-CSI-RS-Resource
// zp-CSI-RS-ResourceId: 0
// resourceMapping
// frequencyDomainAllocation: row4 (2)
// row4: 80 [bit length 3, 5 LSB pad bits, 100. ....
// decimal value 4]
// nrofPorts: p4 (2)
// firstOFDMSymbolInTimeDomain: 8
// cdm-Type: fd-CDM2 (1)
// density: one (1)
// one: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// periodicityAndOffset: slots80 (9)
// slots80: 1
// p-ZP-CSI-RS-ResourceSet: setup (1)
// setup
// zp-CSI-RS-ResourceSetId: 0
// zp-CSI-RS-ResourceIdList: 1 item
// Item 0
// ZP-CSI-RS-ResourceId: 0
srsran_csi_rs_zp_resource_t zp_csi_rs_resource0 = {};
zp_csi_rs_resource0.resource_mapping.row = srsran_csi_rs_resource_mapping_row_4;
zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[0] = true;
zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[1] = false;
zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[2] = false;
zp_csi_rs_resource0.resource_mapping.nof_ports = 4;
zp_csi_rs_resource0.resource_mapping.first_symbol_idx = 8;
zp_csi_rs_resource0.resource_mapping.cdm = srsran_csi_rs_cdm_fd_cdm2;
zp_csi_rs_resource0.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one;
zp_csi_rs_resource0.resource_mapping.freq_band.start_rb = 0;
zp_csi_rs_resource0.resource_mapping.freq_band.nof_rb = 52;
zp_csi_rs_resource0.periodicity.period = 80;
zp_csi_rs_resource0.periodicity.offset = 1;
pdsch.p_zp_csi_rs_set.data[0] = zp_csi_rs_resource0;
pdsch.p_zp_csi_rs_set.count = 1;
// pdsch-ConfigCommon: setup (1)
// setup
@ -648,6 +705,230 @@ struct phy_cfg_nr_t {
harq_ack.dl_data_to_ul_ack[6] = 11;
harq_ack.nof_dl_data_to_ul_ack = 7;
// nzp-CSI-RS-ResourceToAddModList: 5 items
// Item 0
// NZP-CSI-RS-Resource
// nzp-CSI-RS-ResourceId: 0
// resourceMapping
// frequencyDomainAllocation: row2 (1)
// row2: 8000 [bit length 12, 4 LSB pad bits, 1000 0000 0000 .... decimal value 2048]
// nrofPorts: p1 (0)
// firstOFDMSymbolInTimeDomain: 4
// cdm-Type: noCDM (0)
// density: one (1)
// one: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// powerControlOffset: 0dB
// powerControlOffsetSS: db0 (1)
// scramblingID: 0
// periodicityAndOffset: slots80 (9)
// slots80: 1
// qcl-InfoPeriodicCSI-RS: 0
srsran_csi_rs_nzp_resource_t nzp_resource_0 = {};
nzp_resource_0.resource_mapping.row = srsran_csi_rs_resource_mapping_row_2;
nzp_resource_0.resource_mapping.frequency_domain_alloc[0] = true;
nzp_resource_0.resource_mapping.frequency_domain_alloc[1] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[2] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[3] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[4] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[5] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[6] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[7] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[8] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[9] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[10] = false;
nzp_resource_0.resource_mapping.frequency_domain_alloc[11] = false;
nzp_resource_0.resource_mapping.nof_ports = 1;
nzp_resource_0.resource_mapping.first_symbol_idx = 4;
nzp_resource_0.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm;
nzp_resource_0.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one;
nzp_resource_0.resource_mapping.freq_band.start_rb = 0;
nzp_resource_0.resource_mapping.freq_band.nof_rb = 52;
nzp_resource_0.power_control_offset = 0;
nzp_resource_0.power_control_offset_ss = 0;
nzp_resource_0.scrambling_id = 0;
nzp_resource_0.periodicity.period = 80;
nzp_resource_0.periodicity.offset = 1;
// Item 1
// NZP-CSI-RS-Resource
// nzp-CSI-RS-ResourceId: 1
// resourceMapping
// frequencyDomainAllocation: row1 (0)
// row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1]
// nrofPorts: p1 (0)
// firstOFDMSymbolInTimeDomain: 4
// cdm-Type: noCDM (0)
// density: three (2)
// three: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// powerControlOffset: 0dB
// powerControlOffsetSS: db0 (1)
// scramblingID: 0
// periodicityAndOffset: slots40 (7)
// slots40: 11
// qcl-InfoPeriodicCSI-RS: 0
srsran_csi_rs_nzp_resource_t nzp_resource_1 = {};
nzp_resource_1.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
nzp_resource_1.resource_mapping.frequency_domain_alloc[0] = false;
nzp_resource_1.resource_mapping.frequency_domain_alloc[1] = false;
nzp_resource_1.resource_mapping.frequency_domain_alloc[2] = false;
nzp_resource_1.resource_mapping.frequency_domain_alloc[3] = true;
nzp_resource_1.resource_mapping.nof_ports = 1;
nzp_resource_1.resource_mapping.first_symbol_idx = 4;
nzp_resource_1.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm;
nzp_resource_1.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
nzp_resource_1.resource_mapping.freq_band.start_rb = 0;
nzp_resource_1.resource_mapping.freq_band.nof_rb = 52;
nzp_resource_1.power_control_offset = 0;
nzp_resource_1.power_control_offset_ss = 0;
nzp_resource_1.scrambling_id = 0;
nzp_resource_1.periodicity.period = 40;
nzp_resource_1.periodicity.offset = 11;
// Item 2
// NZP-CSI-RS-Resource
// nzp-CSI-RS-ResourceId: 2
// resourceMapping
// frequencyDomainAllocation: row1 (0)
// row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1]
// nrofPorts: p1 (0)
// firstOFDMSymbolInTimeDomain: 8
// cdm-Type: noCDM (0)
// density: three (2)
// three: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// powerControlOffset: 0dB
// powerControlOffsetSS: db0 (1)
// scramblingID: 0
// periodicityAndOffset: slots40 (7)
// slots40: 11
// qcl-InfoPeriodicCSI-RS: 0
srsran_csi_rs_nzp_resource_t nzp_resource_2 = {};
nzp_resource_2.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
nzp_resource_2.resource_mapping.frequency_domain_alloc[0] = false;
nzp_resource_2.resource_mapping.frequency_domain_alloc[1] = false;
nzp_resource_2.resource_mapping.frequency_domain_alloc[2] = false;
nzp_resource_2.resource_mapping.frequency_domain_alloc[3] = true;
nzp_resource_2.resource_mapping.nof_ports = 1;
nzp_resource_2.resource_mapping.first_symbol_idx = 8;
nzp_resource_2.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm;
nzp_resource_2.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
nzp_resource_2.resource_mapping.freq_band.start_rb = 0;
nzp_resource_2.resource_mapping.freq_band.nof_rb = 52;
nzp_resource_2.power_control_offset = 0;
nzp_resource_2.power_control_offset_ss = 0;
nzp_resource_2.scrambling_id = 0;
nzp_resource_2.periodicity.period = 40;
nzp_resource_2.periodicity.offset = 11;
// Item 3
// NZP-CSI-RS-Resource
// nzp-CSI-RS-ResourceId: 3
// resourceMapping
// frequencyDomainAllocation: row1 (0)
// row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1]
// nrofPorts: p1 (0)
// firstOFDMSymbolInTimeDomain: 4
// cdm-Type: noCDM (0)
// density: three (2)
// three: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// powerControlOffset: 0dB
// powerControlOffsetSS: db0 (1)
// scramblingID: 0
// periodicityAndOffset: slots40 (7)
// slots40: 12
// qcl-InfoPeriodicCSI-RS: 0
srsran_csi_rs_nzp_resource_t nzp_resource_3 = {};
nzp_resource_3.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
nzp_resource_3.resource_mapping.frequency_domain_alloc[0] = false;
nzp_resource_3.resource_mapping.frequency_domain_alloc[1] = false;
nzp_resource_3.resource_mapping.frequency_domain_alloc[2] = false;
nzp_resource_3.resource_mapping.frequency_domain_alloc[3] = true;
nzp_resource_3.resource_mapping.nof_ports = 1;
nzp_resource_3.resource_mapping.first_symbol_idx = 4;
nzp_resource_3.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm;
nzp_resource_3.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
nzp_resource_3.resource_mapping.freq_band.start_rb = 0;
nzp_resource_3.resource_mapping.freq_band.nof_rb = 52;
nzp_resource_3.power_control_offset = 0;
nzp_resource_3.power_control_offset_ss = 0;
nzp_resource_3.scrambling_id = 0;
nzp_resource_3.periodicity.period = 40;
nzp_resource_3.periodicity.offset = 12;
// Item 4
// NZP-CSI-RS-Resource
// nzp-CSI-RS-ResourceId: 4
// resourceMapping
// frequencyDomainAllocation: row1 (0)
// row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1]
// nrofPorts: p1 (0)
// firstOFDMSymbolInTimeDomain: 8
// cdm-Type: noCDM (0)
// density: three (2)
// three: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// powerControlOffset: 0dB
// powerControlOffsetSS: db0 (1)
// scramblingID: 0
// periodicityAndOffset: slots40 (7)
// slots40: 12
// qcl-InfoPeriodicCSI-RS: 0
srsran_csi_rs_nzp_resource_t nzp_resource_4 = {};
nzp_resource_4.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
nzp_resource_4.resource_mapping.frequency_domain_alloc[0] = false;
nzp_resource_4.resource_mapping.frequency_domain_alloc[1] = false;
nzp_resource_4.resource_mapping.frequency_domain_alloc[2] = false;
nzp_resource_4.resource_mapping.frequency_domain_alloc[3] = true;
nzp_resource_4.resource_mapping.nof_ports = 1;
nzp_resource_4.resource_mapping.first_symbol_idx = 8;
nzp_resource_4.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm;
nzp_resource_4.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
nzp_resource_4.resource_mapping.freq_band.start_rb = 0;
nzp_resource_4.resource_mapping.freq_band.nof_rb = 52;
nzp_resource_4.power_control_offset = 0;
nzp_resource_4.power_control_offset_ss = 0;
nzp_resource_4.scrambling_id = 0;
nzp_resource_4.periodicity.period = 40;
nzp_resource_4.periodicity.offset = 12;
// zp-CSI-RS-ResourceSetToAddModList: 2 items
// Item 0
// NZP-CSI-RS-ResourceSet
// nzp-CSI-ResourceSetId: 0
// nzp-CSI-RS-Resources: 1 item
// Item 0
// NZP-CSI-RS-ResourceId: 0
pdsch.nzp_csi_rs_sets[0].data[0] = nzp_resource_0;
pdsch.nzp_csi_rs_sets[0].count = 1;
pdsch.nzp_csi_rs_sets[0].trs_info = false;
// Item 1
// NZP-CSI-RS-ResourceSet
// nzp-CSI-ResourceSetId: 1
// nzp-CSI-RS-Resources: 4 items
// Item 0
// NZP-CSI-RS-ResourceId: 1
// Item 1
// NZP-CSI-RS-ResourceId: 2
// Item 2
// NZP-CSI-RS-ResourceId: 3
// Item 3
// NZP-CSI-RS-ResourceId: 4
// trs-Info: true (0)
pdsch.nzp_csi_rs_sets[1].data[0] = nzp_resource_1;
pdsch.nzp_csi_rs_sets[1].data[1] = nzp_resource_2;
pdsch.nzp_csi_rs_sets[1].data[2] = nzp_resource_3;
pdsch.nzp_csi_rs_sets[1].data[3] = nzp_resource_4;
pdsch.nzp_csi_rs_sets[1].count = 4;
pdsch.nzp_csi_rs_sets[1].trs_info = true;
// csi-ReportConfigToAddModList: 1 item
// Item 0
// CSI-ReportConfig

@ -13,95 +13,35 @@
#ifndef SRSRAN_CSI_RS_H_
#define SRSRAN_CSI_RS_H_
#include "srsran/config.h"
#include "srsran/phy/common/phy_common_nr.h"
#include "csi_rs_cfg.h"
#include "srsran/phy/phch/phch_cfg_nr.h"
#include <complex.h>
#include <stdbool.h>
#include <stdint.h>
/**
* @brief Number of frequency domain elements for Row 1
*/
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1 4
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW2 12
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW4 3
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_OTHER 6
#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
* @brief Number of frequency domain elements for Row 2
*/
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;
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW2 12
/**
* @brief Contains CSI-ResourcePeriodicityAndOffset flattened configuration
* @brief Number of frequency domain elements for Row 4
*/
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;
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW4 3
/**
* @brief Contains CSI-RS-ResourceMapping flattened configuration
* @brief Number of frequency domain elements for other rows
*/
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 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;
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_OTHER 6
/**
* @brief Contains NZP-CSI-RS-Resource flattened configuration
* @brief Measurement structure
*/
typedef struct SRSRAN_API {
srsran_csi_rs_resource_mapping_t resource_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;
} srsran_csi_rs_nzp_resource_t;
SRSRAN_API int srsran_csi_rs_nzp_put(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_rs_nzp_resource_t* resource,
cf_t* grid);
typedef struct SRSRAN_API {
float rsrp;
float rsrp_dB;
@ -113,6 +53,35 @@ typedef struct SRSRAN_API {
uint32_t nof_re;
} srsran_csi_rs_measure_t;
/**
* @brief Calculates if the given periodicity implies a CSI-RS transmission in the given slot
* @remark Described in TS 36.211 section 7.4.1.5.3 Mapping to physical resources
* @param periodicity Periodicity configuration
* @param slot_cfg Slot configuration
* @return True if the periodicity configuration matches with the slot, false otherwise
*/
SRSRAN_API bool srsran_csi_rs_send(const srsran_csi_rs_period_and_offset_t* periodicity,
const srsran_slot_cfg_t* slot_cfg);
/**
* @brief Adds to a RE pattern list the RE used in a CSI-RS resource for all CDM grops. This is intended for generating
* reserved RE pattern for PDSCH transmission.
* @param carrier Provides carrier configuration
* @param resource Provides a CSI-RS resource
* @param nof_resources Provides the number of ZP-CSI-RS resources
* @param l Symbol index in the slot
* @param[out] rvd_mask Provides the reserved mask
* @return SRSRAN_SUCCESS if the provided data is valid, and SRSRAN_ERROR code otherwise
*/
SRSRAN_API int srsran_csi_rs_append_resource_to_pattern(const srsran_carrier_nr_t* carrier,
const srsran_csi_rs_resource_mapping_t* resource,
srsran_re_pattern_list_t* re_pattern_list);
SRSRAN_API int srsran_csi_rs_nzp_put(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_rs_nzp_resource_t* resource,
cf_t* grid);
SRSRAN_API int srsran_csi_rs_nzp_measure(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_rs_nzp_resource_t* resource,

@ -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

@ -63,15 +63,14 @@ SRSRAN_API int srsran_dmrs_sch_get_symbols_idx(const srsran_dmrs_sch_cfg_t* dmrs
uint32_t symbols_idx[SRSRAN_DMRS_SCH_MAX_SYMBOLS]);
/**
* @brief Computes the sub-carrier indexes carrying DMRS
*
* @brief Computes the resource element pattern of resource elements reserved for DMRS
* @param cfg PDSCH DMRS configuration provided by upper layers
* @param max_count is the number of sub-carriers to generate
* @param sc_idx is the destination pointer where the sub-carrier indexes are stored
*
* @return It returns the number of sub-carriers if inputs are valid, otherwise, it returns SRSRAN_ERROR code.
* @param[out] pattern Provides the RE pattern to fill
* @return SRSRAN_SUCCESS if computation is successful, SRSRAN_ERROR code otherwise
*/
SRSRAN_API int srsran_dmrs_sch_get_sc_idx(const srsran_dmrs_sch_cfg_t* cfg, uint32_t max_count, uint32_t* sc_idx);
SRSRAN_API int srsran_dmrs_sch_rvd_re_pattern(const srsran_dmrs_sch_cfg_t* cfg,
const srsran_sch_grant_nr_t* grant,
srsran_re_pattern_t* pattern);
/**
* @brief Calculates the number of resource elements taken by a PDSCH-DMRS for a given PDSCH transmission
@ -143,8 +142,8 @@ SRSRAN_API int srsran_dmrs_sch_put_sf(srsran_dmrs_sch_t* q,
* @attention Current implementation supports only type1 PDSCH DMRS (1 pilot every 2 RE)
*
* @param q DMRS-PDSCH object
* @param slot_cfg Slot configuration
* @param pdsch_cfg PDSCH configuration provided by upper layers
* @param slot Slot configuration
* @param cfg PDSCH configuration provided by upper layers
* @param grant PDSCH information provided by a DCI
* @param sf_symbols Received resource grid
* @param[out] ce Channel estimates
@ -152,8 +151,8 @@ SRSRAN_API int srsran_dmrs_sch_put_sf(srsran_dmrs_sch_t* q,
* @return it returns SRSRAN_ERROR code if an error occurs, otherwise it returns SRSRAN_SUCCESS
*/
SRSRAN_API int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_sch_cfg_nr_t* pdsch_cfg,
const srsran_slot_cfg_t* slot,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const cf_t* sf_symbols,
srsran_chest_dl_res_t* chest_res);

@ -26,6 +26,7 @@
* @brief Maximum number of CSI-RS resources defined in TS 38.331 maxNrofCSI-ResourceConfigurations
*/
#define SRSRAN_CSI_MAX_NOF_RESOURCES 112
/**
* @brief CSI report types defined in TS 38.331 CSI-ReportConfig
*/

@ -55,6 +55,8 @@ typedef struct SRSRAN_API {
srsran_evm_buffer_t* evm_buffer;
bool meas_time_en;
uint32_t meas_time_us;
srsran_re_pattern_t dmrs_re_pattern;
uint32_t nof_rvd_re;
} srsran_pdsch_nr_t;
/**

@ -21,9 +21,17 @@
#ifndef SRSRAN_PHCH_CFG_NR_H
#define SRSRAN_PHCH_CFG_NR_H
#include "srsran/phy/ch_estimation/csi_rs_cfg.h"
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/phch/sch_cfg_nr.h"
#include "srsran/phy/phch/uci_cfg_nr.h"
#include "srsran/phy/utils/re_pattern.h"
/**
* @brief Specifies the maximum number of ZP-CSI-RS resources configured per slot. It is not implicitly specified in the
* TS.
*/
#define SRSRAN_PHCH_CFG_MAX_NOF_ZP_CSI_RS_RES_PER_SLOT 16
/**
* @brief PDSCH DMRS type
@ -203,6 +211,12 @@ typedef struct SRSRAN_API {
srsran_sch_cfg_t sch_cfg; ///< Common shared channel parameters
/// PDSCH Periodic ZP-CSI-RS set
srsran_csi_rs_zp_set_t p_zp_csi_rs_set;
/// PDSCH Periodic NZP-CSI-RS set, indexed by nzp-CSI-ResourceSetId
srsran_csi_rs_nzp_set_t nzp_csi_rs_sets[SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS];
/// PUSCH only
srsran_beta_offsets_t beta_offsets; /// Semi-static only.
float scaling; /// Indicates a scaling factor to limit the number of resource elements assigned to UCI on PUSCH.
@ -213,12 +227,12 @@ typedef struct SRSRAN_API {
*/
typedef struct SRSRAN_API {
bool scrambling_id_present;
uint32_t scambling_id; // Identifier used to initialize data scrambling (0-1023)
uint32_t scambling_id; ///< Identifier used to initialize data scrambling (0-1023)
srsran_dmrs_sch_cfg_t dmrs;
srsran_sch_grant_nr_t grant;
srsran_sch_cfg_t sch_cfg; ///< Common shared channel parameters
srsran_dmrs_sch_cfg_t dmrs; ///< DMRS configuration for this transmission
srsran_sch_grant_nr_t grant; ///< Actual SCH grant
srsran_sch_cfg_t sch_cfg; ///< Common shared channel parameters
srsran_re_pattern_list_t rvd_re; ///< Reserved resource elements, as pattern
/// PUSCH only parameters
srsran_uci_cfg_nr_t uci; ///< Uplink Control Information configuration

@ -90,12 +90,14 @@ SRSRAN_API int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg,
* Note: Only TypeA PDSCH mapping type is supported
*
* @param carrier Carrier information struct
* @param slot Slot configuration
* @param pdsch_cfg PDSCH configuration indicated by higher layers
* @param dci_dl DCI downlink (format 1_0 or 1_1)
* @param pdsch_grant Generated PDSCH grant
* @return 0 on success, -1 on error
*/
SRSRAN_API int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot,
const srsran_sch_hl_cfg_nr_t* pdsch_cfg,
const srsran_dci_dl_nr_t* dci_dl,
srsran_sch_cfg_nr_t* cfg,

@ -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

@ -181,6 +181,7 @@ SRSRAN_API void srsran_vec_prod_sss(const int16_t* x, const int16_t* y, int16_t*
// Negate sign (scrambling)
SRSRAN_API void srsran_vec_neg_sss(const int16_t* x, const int16_t* y, int16_t* z, const uint32_t len);
SRSRAN_API void srsran_vec_neg_bbb(const int8_t* x, const int8_t* y, int8_t* z, const uint32_t len);
SRSRAN_API void srsran_vec_neg_bb(const int8_t* x, int8_t* z, const uint32_t len);
/* Dot-product */
SRSRAN_API cf_t srsran_vec_dot_prod_cfc(const cf_t* x, const float* y, const uint32_t len);

@ -12,23 +12,27 @@
#include "srsran/phy/ch_estimation/csi_rs.h"
#include "srsran/phy/common/sequence.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
#include <complex.h>
#include <stdbool.h>
#include <stdint.h>
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1 4
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW2 12
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW4 3
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_OTHER 6
#define SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_MAX 12
/**
* @brief Maximum number of subcarriers occupied by a CSI-RS resource as defined in TS 38.211 Table 7.4.1.5.3-1
*/
#define CSI_RS_MAX_SUBC_PRB 4
#define CSI_RS_MAX_CDM_GROUP 16
/**
* @brief Maximum number of symbols occupied by a CSI-RS resource as defined in TS 38.211 Table 7.4.1.5.3-1
*/
#define CSI_RS_MAX_SYMBOLS_SLOT 4
static int csi_rs_location_f(const srsran_csi_rs_resource_mapping_t* resource, uint32_t i)
{
uint32_t count = 0;
uint32_t nof_freq_domain = 0;
uint32_t mul = 1;
switch (resource->row) {
case srsran_csi_rs_resource_mapping_row_1:
nof_freq_domain = SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1;
@ -38,28 +42,32 @@ static int csi_rs_location_f(const srsran_csi_rs_resource_mapping_t* resource, u
break;
case srsran_csi_rs_resource_mapping_row_4:
nof_freq_domain = SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW4;
mul = 4;
break;
case srsran_csi_rs_resource_mapping_row_other:
nof_freq_domain = SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_OTHER;
mul = 2;
break;
}
for (uint32_t j = 0; j < nof_freq_domain; j++) {
if (resource->frequency_domain_alloc[j]) {
if (resource->frequency_domain_alloc[nof_freq_domain - 1 - j]) {
count++;
}
if (count == i) {
return i;
return j * mul;
}
}
ERROR("Unhandled configuration");
return SRSRAN_ERROR;
}
// Table 7.4.1.5.3-1: CSI-RS locations within a slot
static int csi_rs_location_get_k_list(const srsran_csi_rs_resource_mapping_t* resource,
uint32_t k_list[CSI_RS_MAX_CDM_GROUP])
uint32_t j,
uint32_t k_list[CSI_RS_MAX_SUBC_PRB])
{
int k0 = csi_rs_location_f(resource, 1);
// int k1 = csi_rs_location_f(resource, 2);
@ -71,20 +79,49 @@ static int csi_rs_location_get_k_list(const srsran_csi_rs_resource_mapping_t* re
}
// Row 1
if (resource->row == srsran_csi_rs_resource_mapping_row_1 && resource->ports == 1 &&
resource->density == srsran_csi_rs_resource_mapping_density_three && resource->cdm == srsran_csi_rs_cdm_nocdm) {
if (resource->row == srsran_csi_rs_resource_mapping_row_1 && resource->nof_ports == 1 &&
resource->density == srsran_csi_rs_resource_mapping_density_three && resource->cdm == srsran_csi_rs_cdm_nocdm &&
j == 0) {
k_list[0] = k0;
k_list[1] = k0 + 4;
k_list[2] = k0 + 8;
return 3;
}
// Row 2
if (resource->row == srsran_csi_rs_resource_mapping_row_2 && resource->nof_ports == 1 &&
resource->cdm == srsran_csi_rs_cdm_nocdm) {
if (resource->density == srsran_csi_rs_resource_mapping_density_one ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_even ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_odd) {
k_list[0] = k0;
return 1;
}
}
// Row 4
if (resource->row == srsran_csi_rs_resource_mapping_row_4 && resource->nof_ports == 4 &&
resource->density == srsran_csi_rs_resource_mapping_density_one && resource->cdm == srsran_csi_rs_cdm_fd_cdm2) {
if (j == 0) {
k_list[0] = k0;
k_list[1] = k0 + 1;
return 2;
}
if (j == 1) {
k_list[0] = k0 + 2;
k_list[1] = k0 + 2 + 1;
return 2;
}
}
ERROR("Unhandled configuration");
return SRSRAN_ERROR;
}
// Table 7.4.1.5.3-1: CSI-RS locations within a slot
static int csi_rs_location_get_l_list(const srsran_csi_rs_resource_mapping_t* resource,
uint32_t l_list[CSI_RS_MAX_CDM_GROUP])
uint32_t j,
uint32_t l_list[CSI_RS_MAX_SYMBOLS_SLOT])
{
uint32_t l0 = resource->first_symbol_idx;
@ -98,19 +135,44 @@ static int csi_rs_location_get_l_list(const srsran_csi_rs_resource_mapping_t* re
// }
// Row 1
if (resource->row == srsran_csi_rs_resource_mapping_row_1 && resource->ports == 1 &&
if (resource->row == srsran_csi_rs_resource_mapping_row_1 && resource->nof_ports == 1 &&
resource->density == srsran_csi_rs_resource_mapping_density_three && resource->cdm == srsran_csi_rs_cdm_nocdm) {
l_list[0] = l0;
return 1;
}
// Row 2
if (resource->row == srsran_csi_rs_resource_mapping_row_2 && resource->nof_ports == 1 &&
resource->cdm == srsran_csi_rs_cdm_nocdm) {
if (resource->density == srsran_csi_rs_resource_mapping_density_one ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_even ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_odd) {
l_list[0] = l0;
return 1;
}
}
// Row 4
if (resource->row == srsran_csi_rs_resource_mapping_row_4 && resource->nof_ports == 4 &&
resource->density == srsran_csi_rs_resource_mapping_density_one && resource->cdm == srsran_csi_rs_cdm_fd_cdm2) {
if (j == 0) {
l_list[0] = l0;
return 1;
}
if (j == 1) {
l_list[0] = l0;
return 1;
}
}
ERROR("Unhandled configuration");
return SRSRAN_ERROR;
}
uint32_t csi_rs_cinit(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_rs_nzp_resource_t* resource,
uint32_t l)
static uint32_t csi_rs_cinit(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_rs_nzp_resource_t* resource,
uint32_t l)
{
uint32_t n = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx);
uint32_t n_id = resource->scrambling_id;
@ -118,7 +180,7 @@ uint32_t csi_rs_cinit(const srsran_carrier_nr_t* carrier,
return ((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id) << 10UL) + n_id;
}
bool srsran_csi_send(const srsran_csi_rs_period_and_offset_t* periodicity, const srsran_slot_cfg_t* slot_cfg)
bool srsran_csi_rs_send(const srsran_csi_rs_period_and_offset_t* periodicity, const srsran_slot_cfg_t* slot_cfg)
{
if (periodicity == NULL || slot_cfg == NULL) {
return false;
@ -133,6 +195,43 @@ bool srsran_csi_send(const srsran_csi_rs_period_and_offset_t* periodicity, const
return n == 0;
}
static int csi_rs_nof_cdm_groups(const srsran_csi_rs_resource_mapping_t* resource)
{
if (resource->row == srsran_csi_rs_resource_mapping_row_1 && resource->nof_ports == 1 &&
resource->density == srsran_csi_rs_resource_mapping_density_three && resource->cdm == srsran_csi_rs_cdm_nocdm) {
return 1;
}
// Row 1
if (resource->row == srsran_csi_rs_resource_mapping_row_2 && resource->nof_ports == 1 &&
resource->cdm == srsran_csi_rs_cdm_nocdm) {
if (resource->density == srsran_csi_rs_resource_mapping_density_one ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_even ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_odd) {
return 1;
}
}
// Row 2
if (resource->row == srsran_csi_rs_resource_mapping_row_2 && resource->nof_ports == 1 &&
resource->cdm == srsran_csi_rs_cdm_nocdm) {
if (resource->density == srsran_csi_rs_resource_mapping_density_one ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_even ||
resource->density == srsran_csi_rs_resource_mapping_density_dot5_odd) {
return 1;
}
}
// Row 3
if (resource->row == srsran_csi_rs_resource_mapping_row_4 && resource->nof_ports == 4 &&
resource->density == srsran_csi_rs_resource_mapping_density_one && resource->cdm == srsran_csi_rs_cdm_fd_cdm2) {
return 2;
}
ERROR("Unhandled configuration");
return SRSRAN_ERROR;
}
uint32_t csi_rs_count(srsran_csi_rs_density_t density, uint32_t nprb)
{
switch (density) {
@ -150,7 +249,7 @@ uint32_t csi_rs_count(srsran_csi_rs_density_t density, uint32_t nprb)
return 0;
}
uint32_t csi_rs_rb_begin(const srsran_carrier_nr_t* carrier, const srsran_csi_rs_resource_mapping_t* m)
static uint32_t csi_rs_rb_begin(const srsran_carrier_nr_t* carrier, const srsran_csi_rs_resource_mapping_t* m)
{
uint32_t ret = SRSRAN_MAX(carrier->start, m->freq_band.start_rb);
@ -162,12 +261,12 @@ uint32_t csi_rs_rb_begin(const srsran_carrier_nr_t* carrier, const srsran_csi_rs
return ret;
}
uint32_t csi_rs_rb_end(const srsran_carrier_nr_t* carrier, const srsran_csi_rs_resource_mapping_t* m)
static uint32_t csi_rs_rb_end(const srsran_carrier_nr_t* carrier, const srsran_csi_rs_resource_mapping_t* m)
{
return SRSRAN_MIN(carrier->start + carrier->nof_prb, m->freq_band.start_rb + m->freq_band.nof_rb);
}
uint32_t csi_rs_rb_stride(const srsran_csi_rs_resource_mapping_t* m)
static uint32_t csi_rs_rb_stride(const srsran_csi_rs_resource_mapping_t* m)
{
uint32_t ret = 1;
@ -181,6 +280,65 @@ uint32_t csi_rs_rb_stride(const srsran_csi_rs_resource_mapping_t* m)
return ret;
}
int srsran_csi_rs_append_resource_to_pattern(const srsran_carrier_nr_t* carrier,
const srsran_csi_rs_resource_mapping_t* resource,
srsran_re_pattern_list_t* re_pattern_list)
{
// Check inputs
if (resource == NULL || re_pattern_list == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Create temporal pattern
srsran_re_pattern_t pattern = {};
pattern.rb_begin = csi_rs_rb_begin(carrier, resource);
pattern.rb_end = csi_rs_rb_end(carrier, resource);
pattern.rb_stride = csi_rs_rb_stride(resource);
// Calculate number of CDM groups
int nof_cdm_groups = csi_rs_nof_cdm_groups(resource);
if (nof_cdm_groups < SRSRAN_SUCCESS) {
ERROR("Error getting number of CDM groups");
return SRSRAN_ERROR;
}
// Iterate over all CDM groups
for (int j = 0; j < nof_cdm_groups; j++) {
// Get SC indexes
uint32_t k_list[CSI_RS_MAX_SUBC_PRB] = {};
int nof_k = csi_rs_location_get_k_list(resource, j, k_list);
if (nof_k < SRSRAN_SUCCESS) {
ERROR("Error getting indexes for CSI-RS");
return SRSRAN_ERROR;
}
// Fill subcarrier mask
for (int k = 0; k < nof_k; k++) {
pattern.sc[k_list[k]] = true;
}
// Get OFDM symbol indexes
uint32_t l_list[CSI_RS_MAX_SUBC_PRB] = {};
int nof_l = csi_rs_location_get_l_list(resource, j, l_list);
if (nof_l < SRSRAN_SUCCESS) {
ERROR("Error getting indexes for CSI-RS");
return SRSRAN_ERROR;
}
// Fill OFDM symbol mask
for (int l = 0; l < nof_l; l++) {
pattern.symbol[l_list[l]] = true;
}
if (srsran_re_pattern_merge(re_pattern_list, &pattern) < SRSRAN_SUCCESS) {
ERROR("Error merging pattern");
return SRSRAN_ERROR;
}
}
return SRSRAN_SUCCESS;
}
int srsran_csi_rs_nzp_put(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_rs_nzp_resource_t* resource,
@ -190,14 +348,17 @@ int srsran_csi_rs_nzp_put(const srsran_carrier_nr_t* carrier,
return SRSRAN_ERROR;
}
uint32_t k_list[CSI_RS_MAX_CDM_GROUP];
int nof_k = csi_rs_location_get_k_list(&resource->resource_mapping, k_list);
// Force CDM group to 0
uint32_t j = 0;
uint32_t k_list[CSI_RS_MAX_SUBC_PRB];
int nof_k = csi_rs_location_get_k_list(&resource->resource_mapping, j, k_list);
if (nof_k <= 0) {
return SRSRAN_ERROR;
}
uint32_t l_list[CSI_RS_MAX_CDM_GROUP];
int nof_l = csi_rs_location_get_l_list(&resource->resource_mapping, l_list);
uint32_t l_list[CSI_RS_MAX_SYMBOLS_SLOT];
int nof_l = csi_rs_location_get_l_list(&resource->resource_mapping, j, l_list);
if (nof_l <= 0) {
return SRSRAN_ERROR;
}
@ -261,14 +422,17 @@ int srsran_csi_rs_nzp_measure(const srsran_carrier_nr_t* carrier,
return SRSRAN_ERROR;
}
uint32_t k_list[CSI_RS_MAX_CDM_GROUP];
int nof_k = csi_rs_location_get_k_list(&resource->resource_mapping, k_list);
// Force CDM group to 0
uint32_t j = 0;
uint32_t k_list[CSI_RS_MAX_SUBC_PRB];
int nof_k = csi_rs_location_get_k_list(&resource->resource_mapping, j, k_list);
if (nof_k <= 0) {
return SRSRAN_ERROR;
}
uint32_t l_list[CSI_RS_MAX_CDM_GROUP];
int nof_l = csi_rs_location_get_l_list(&resource->resource_mapping, l_list);
uint32_t l_list[CSI_RS_MAX_SYMBOLS_SLOT];
int nof_l = csi_rs_location_get_l_list(&resource->resource_mapping, j, l_list);
if (nof_l <= 0) {
return SRSRAN_ERROR;
}

@ -25,6 +25,7 @@
#define DMRS_PDCCH_INFO_TX(...) INFO("PDCCH DMRS Tx: " __VA_ARGS__)
#define DMRS_PDCCH_INFO_RX(...) INFO("PDCCH DMRS Rx: " __VA_ARGS__)
#define DMRS_PDCCH_DEBUG_RX(...) DEBUG("PDCCH DMRS Rx: " __VA_ARGS__)
/// @brief Enables interpolation at CCE frequency bandwidth to avoid interference with adjacent PDCCH DMRS
#define DMRS_PDCCH_INTERPOLATE_GROUP 1
@ -347,8 +348,6 @@ int srsran_dmrs_pdcch_estimate(srsran_dmrs_pdcch_estimator_t* q,
// Calculate PRN sequence initial state
uint32_t cinit = dmrs_pdcch_get_cinit(slot_idx, l, n_id);
DMRS_PDCCH_INFO_RX("n=%d; l=%d; cinit=%08x", slot_idx, l, cinit);
// Extract pilots least square estimates
srsran_dmrs_pdcch_extract(q, cinit, &sf_symbols[l * q->carrier.nof_prb * SRSRAN_NRE], q->lse[l]);
}
@ -410,8 +409,8 @@ int srsran_dmrs_pdcch_get_measure(const srsran_dmrs_pdcch_estimator_t* q,
float sync_err = 0.0f;
cf_t corr[SRSRAN_CORESET_DURATION_MAX] = {};
for (uint32_t l = 0; l < q->coreset.duration; l++) {
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_INFO && !handler_registered) {
DMRS_PDCCH_INFO_RX("Measuring PDCCH l=%d; lse=", l);
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DMRS_PDCCH_DEBUG_RX("Measuring PDCCH l=%d; lse=", l);
srsran_vec_fprint_c(stdout, &q->lse[l][pilot_idx], nof_pilots);
}

@ -11,6 +11,7 @@
*/
#include "srsran/phy/ch_estimation/dmrs_sch.h"
#include "srsran/phy/ch_estimation/csi_rs.h"
#include "srsran/phy/common/sequence.h"
#include <complex.h>
#include <srsran/phy/utils/debug.h>
@ -399,26 +400,56 @@ int srsran_dmrs_sch_get_symbols_idx(const srsran_dmrs_sch_cfg_t* dmrs_cfg,
return SRSRAN_ERROR;
}
int srsran_dmrs_sch_get_sc_idx(const srsran_dmrs_sch_cfg_t* cfg, uint32_t max_count, uint32_t* sc_idx)
int srsran_dmrs_sch_rvd_re_pattern(const srsran_dmrs_sch_cfg_t* cfg,
const srsran_sch_grant_nr_t* grant,
srsran_re_pattern_t* pattern)
{
int count = 0;
uint32_t delta = 0;
if (cfg == NULL || pattern == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Initialise pattern with zeros
SRSRAN_MEM_ZERO(pattern, srsran_re_pattern_t, 1);
// Fill RB bounds
pattern->rb_begin = 0;
pattern->rb_end = SRSRAN_MAX_PRB_NR;
pattern->rb_stride = 1;
// Fill subcarrier mask
if (cfg->type == srsran_dmrs_sch_type_1) {
for (uint32_t n = 0; count < max_count; n += 4) {
for (uint32_t k_prime = 0; k_prime < 2 && count < max_count; k_prime++) {
sc_idx[count++] = n + 2 * k_prime + delta;
for (uint32_t n = 0; n < 3; n++) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++) {
for (uint32_t delta = 0; delta < grant->nof_dmrs_cdm_groups_without_data; delta++) {
pattern->sc[(4 * n + 2 * k_prime + delta) % SRSRAN_NRE] = true;
}
}
}
} else {
for (uint32_t n = 0; count < max_count; n += 6) {
for (uint32_t k_prime = 0; k_prime < 2 && count < max_count; k_prime++) {
sc_idx[count++] = n + k_prime + delta;
for (uint32_t n = 0; n < 2; n++) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++) {
for (uint32_t delta = 0; delta < grant->nof_dmrs_cdm_groups_without_data; delta++) {
pattern->sc[(6 * n + k_prime + 2 * delta) % SRSRAN_NRE] = true;
}
}
}
}
return count;
// Calculate OFDM symbols
uint32_t symbols[SRSRAN_DMRS_SCH_MAX_SYMBOLS];
int nof_l = srsran_dmrs_sch_get_symbols_idx(cfg, grant, symbols);
if (nof_l < SRSRAN_SUCCESS) {
ERROR("Error calculating OFDM symbols");
return SRSRAN_ERROR;
}
// Set OFDM symbol mask
for (int i = 0; i < nof_l; i++) {
uint32_t l = symbols[i];
pattern->symbol[l % SRSRAN_NSYMB_PER_SLOT_NR] = true;
}
return SRSRAN_SUCCESS;
}
int srsran_dmrs_sch_get_N_prb(const srsran_dmrs_sch_cfg_t* dmrs_cfg, const srsran_sch_grant_nr_t* grant)
@ -666,26 +697,26 @@ static int srsran_dmrs_sch_get_symbol(srsran_dmrs_sch_t* q,
}
int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_sch_cfg_nr_t* pdsch_cfg,
const srsran_slot_cfg_t* slot,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const cf_t* sf_symbols,
srsran_chest_dl_res_t* chest_res)
{
const uint32_t delta = 0;
if (q == NULL || slot_cfg == NULL || sf_symbols == NULL || chest_res == NULL) {
if (q == NULL || slot == NULL || sf_symbols == NULL || chest_res == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
const srsran_dmrs_sch_cfg_t* dmrs_cfg = &pdsch_cfg->dmrs;
const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs;
cf_t* ce = q->temp;
uint32_t symbol_sz = q->carrier.nof_prb * SRSRAN_NRE; // Symbol size in resource elements
// Get symbols indexes
uint32_t symbols[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {};
int nof_symbols = srsran_dmrs_sch_get_symbols_idx(&pdsch_cfg->dmrs, grant, symbols);
int nof_symbols = srsran_dmrs_sch_get_symbols_idx(&cfg->dmrs, grant, symbols);
if (nof_symbols <= SRSRAN_SUCCESS) {
ERROR("Error getting symbol indexes");
return SRSRAN_ERROR;
@ -697,11 +728,11 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
for (uint32_t i = 0; i < nof_symbols; i++) {
uint32_t l = symbols[i]; // Symbol index inside the slot
uint32_t cinit = srsran_dmrs_sch_seed(
&q->carrier, pdsch_cfg, grant, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx), l);
uint32_t cinit =
srsran_dmrs_sch_seed(&q->carrier, cfg, grant, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot->idx), l);
nof_pilots_x_symbol = srsran_dmrs_sch_get_symbol(
q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]);
q, cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]);
if (nof_pilots_x_symbol == 0) {
ERROR("Error, no pilots extracted (i=%d, l=%d)", i, l);
@ -784,6 +815,26 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
symbol_idx++;
}
// Initialise reserved mask
bool rvd_mask_wb[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {};
// Compute reserved RE
if (srsran_re_pattern_list_to_symbol_mask(&cfg->rvd_re, l, rvd_mask_wb) < SRSRAN_SUCCESS) {
ERROR("Error generating reserved RE mask");
return SRSRAN_ERROR;
}
// Narrow reserved subcarriers to the ones used in the transmission
bool rvd_mask[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {};
for (uint32_t i = 0, k = 0; i < q->carrier.nof_prb; i++) {
if (grant->prb_idx[i]) {
for (uint32_t j = 0; j < SRSRAN_NRE; j++) {
rvd_mask[k++] = rvd_mask_wb[i * SRSRAN_NRE + j];
}
}
}
// Check if it s DMRS symbol
if (symbols[symbol_idx] == l) {
switch (dmrs_cfg->type) {
case srsran_dmrs_sch_type_1:
@ -792,8 +843,9 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
continue;
}
for (uint32_t i = 1; i < nof_re_x_symbol; i += 2) {
chest_res->ce[0][0][count] = ce[i];
count++;
if (!rvd_mask[i]) {
chest_res->ce[0][0][count++] = ce[i];
}
}
break;
case srsran_dmrs_sch_type_2:
@ -803,14 +855,20 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
}
for (uint32_t i = grant->nof_dmrs_cdm_groups_without_data * 2; i < nof_re_x_symbol; i += 6) {
uint32_t nof_re = (3 - grant->nof_dmrs_cdm_groups_without_data) * 2;
srsran_vec_cf_copy(&chest_res->ce[0][0][count], &ce[i], nof_re);
count += nof_re;
for (uint32_t j = 0; j < nof_re; j++) {
if (!rvd_mask[i + j]) {
chest_res->ce[0][0][count++] = ce[i + j];
}
}
}
break;
}
} else {
srsran_vec_cf_copy(&chest_res->ce[0][0][count], ce, nof_re_x_symbol);
count += nof_re_x_symbol;
for (uint32_t i = 0; i < nof_re_x_symbol; i++) {
if (!rvd_mask[i]) {
chest_res->ce[0][0][count++] = ce[i];
}
}
}
}
// Set other values in the estimation result

@ -77,7 +77,7 @@ add_lte_test(chest_test_sl_psbch chest_test_sl)
add_executable(dmrs_pdsch_test dmrs_pdsch_test.c)
target_link_libraries(dmrs_pdsch_test srsran_phy)
add_lte_test(dmrs_pdsch_test dmrs_pdsch_test)
add_nr_test(dmrs_pdsch_test dmrs_pdsch_test)
########################################################################
@ -87,7 +87,7 @@ add_lte_test(dmrs_pdsch_test dmrs_pdsch_test)
add_executable(dmrs_pdcch_test dmrs_pdcch_test.c)
target_link_libraries(dmrs_pdcch_test srsran_phy)
add_lte_test(dmrs_pdcch_test dmrs_pdcch_test)
add_nr_test(dmrs_pdcch_test dmrs_pdcch_test)
########################################################################
@ -97,5 +97,15 @@ add_lte_test(dmrs_pdcch_test dmrs_pdcch_test)
add_executable(csi_rs_test csi_rs_test.c)
target_link_libraries(csi_rs_test srsran_phy)
add_lte_test(csi_rs_test csi_rs_test -o 3 -S 0 -L 150 -f 3 -p 15)
add_nr_test(csi_rs_test csi_rs_test -o 3 -S 0 -L 150 -f 3 -p 15)
########################################################################
# NR CSI RS Pattern test
########################################################################
add_executable(csi_rs_pattern_test csi_rs_pattern_test.c)
target_link_libraries(csi_rs_pattern_test srsran_phy)
add_nr_test(csi_rs_pattern_test csi_rs_pattern_test)

@ -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;
}

@ -136,10 +136,10 @@ int main(int argc, char** argv)
}
// Fixed parameters, other params are not implemented
resource.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm;
resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
resource.resource_mapping.ports = 1;
resource.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm;
resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
resource.resource_mapping.nof_ports = 1;
// Row 1 supported only!
uint32_t nof_freq_dom_alloc = SRSRAN_CSI_RS_NOF_FREQ_DOMAIN_ALLOC_ROW1;

@ -164,41 +164,44 @@ static int assert_cfg(const srsran_sch_cfg_nr_t* pdsch_cfg, const srsran_sch_gra
continue;
}
if (grant->mapping != gold[i].mapping_type) {
// Skip golden sample if one of the parameters does not match
if (grant->mapping != gold[i].mapping_type || pdsch_cfg->dmrs.typeA_pos != gold[i].typeA_pos ||
pdsch_cfg->dmrs.additional_pos != gold[i].additional_pos || pdsch_cfg->dmrs.length != gold[i].max_length ||
pdsch_cfg->dmrs.type != gold[i].type) {
continue;
}
if (pdsch_cfg->dmrs.typeA_pos != gold[i].typeA_pos) {
continue;
}
if (pdsch_cfg->dmrs.additional_pos != gold[i].additional_pos) {
continue;
}
if (pdsch_cfg->dmrs.length != gold[i].max_length) {
continue;
}
if (pdsch_cfg->dmrs.type != gold[i].type) {
continue;
// Generate subcarrier mask from golden sample
bool sc_mask[SRSRAN_NRE] = {};
if (grant->nof_dmrs_cdm_groups_without_data == 1) {
for (uint32_t j = 0; j < gold[i].nof_sc; j++) {
sc_mask[gold[i].sc_idx[j] % SRSRAN_NRE] = true;
}
} else if (pdsch_cfg->dmrs.type == srsran_dmrs_sch_type_1) {
for (uint32_t k = 0; k < SRSRAN_NRE; k++) {
sc_mask[k] = true;
}
} else if (pdsch_cfg->dmrs.type == srsran_dmrs_sch_type_2) {
for (uint32_t k = 0; k < SRSRAN_NRE; k++) {
sc_mask[k] = ((k % 6) < grant->nof_dmrs_cdm_groups_without_data * 2);
}
}
uint32_t symbols[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {};
int nof_symbols = srsran_dmrs_sch_get_symbols_idx(&pdsch_cfg->dmrs, grant, symbols);
TESTASSERT(nof_symbols == gold[i].nof_symbols);
// Generate symbol mask from golden sample
bool symbol_mask[SRSRAN_NSYMB_PER_SLOT_NR] = {};
for (uint32_t j = 0; j < gold[i].nof_symbols; j++) {
TESTASSERT(symbols[j] == gold[i].symbol_idx[j]);
symbol_mask[gold[i].symbol_idx[j] % SRSRAN_NSYMB_PER_SLOT_NR] = true;
}
uint32_t sc[SRSRAN_NRE] = {};
srsran_dmrs_sch_get_sc_idx(&pdsch_cfg->dmrs, SRSRAN_NRE, sc);
// Generate DMRS pattern
srsran_re_pattern_t pattern = {};
TESTASSERT(srsran_dmrs_sch_rvd_re_pattern(&pdsch_cfg->dmrs, grant, &pattern) == SRSRAN_SUCCESS);
for (uint32_t j = 0; j < gold[i].nof_sc; j++) {
TESTASSERT(sc[j] == gold[i].sc_idx[j]);
}
// Assert subcarrier mask
TESTASSERT(memcmp(pattern.sc, sc_mask, sizeof(bool) * SRSRAN_NRE) == 0);
// Assert symbol mask
TESTASSERT(memcmp(pattern.symbol, symbol_mask, sizeof(bool) * SRSRAN_NSYMB_PER_SLOT_NR) == 0);
return SRSRAN_SUCCESS;
}
@ -307,7 +310,15 @@ int main(int argc, char** argv)
for (grant.nof_dmrs_cdm_groups_without_data = 1; grant.nof_dmrs_cdm_groups_without_data <= 3;
grant.nof_dmrs_cdm_groups_without_data++) {
// Load default type A grant
srsran_ra_dl_nr_time_default_A(0, pdsch_cfg.dmrs.typeA_pos, &grant);
if (srsran_ra_dl_nr_time_default_A(m, pdsch_cfg.dmrs.typeA_pos, &grant) < SRSRAN_SUCCESS) {
ERROR("Error loading time resource");
continue;
}
// Mapping type B is not supported
if (grant.mapping == srsran_sch_mapping_type_B) {
continue;
}
int n = run_test(&dmrs_pdsch, &pdsch_cfg, &grant, sf_symbols, &chest_dl_res);

@ -11,6 +11,7 @@
*/
#include "srsran/phy/phch/pdsch_nr.h"
#include "srsran/phy/ch_estimation/csi_rs.h"
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/mimo/layermap.h"
#include "srsran/phy/mimo/precoding.h"
@ -174,171 +175,25 @@ void srsran_pdsch_nr_free(srsran_pdsch_nr_t* q)
}
}
/**
* @brief copies a number of countiguous Resource Elements
* @param sf_symbols slot symbols in frequency domain
* @param symbols resource elements
* @param count number of resource elements to copy
* @param put Direction, symbols are copied into sf_symbols if put is true, otherwise sf_symbols are copied into symbols
*/
static void srsran_pdsch_re_cp(cf_t* sf_symbols, cf_t* symbols, uint32_t count, bool put)
{
if (put) {
srsran_vec_cf_copy(sf_symbols, symbols, count);
} else {
srsran_vec_cf_copy(symbols, sf_symbols, count);
}
}
/*
* As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with group 2:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* -- k -->
*
* If the number of DMRS CDM groups without data is set to:
* - 1, data is mapped in RE marked as 2
* - Otherwise, no data is mapped in this symbol
*/
static uint32_t srsran_pdsch_nr_cp_dmrs_type1(const srsran_pdsch_nr_t* q,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
static inline uint32_t pdsch_nr_put_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
{
uint32_t count = 0;
uint32_t delta = 0;
if (grant->nof_dmrs_cdm_groups_without_data != 1) {
return count;
}
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
if (grant->prb_idx[i]) {
for (uint32_t j = 0; j < SRSRAN_NRE; j += 2) {
if (put) {
sf_symbols[i * SRSRAN_NRE + delta + j + 1] = symbols[count++];
} else {
symbols[count++] = sf_symbols[i * SRSRAN_NRE + delta + j + 1];
}
}
for (uint32_t i = 0; i < SRSRAN_NRE; i++) {
if (!rvd_mask[i]) {
dst[i] = src[count++];
}
}
return count;
}
/*
* As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with groups 2 and 3:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | 1 | 1 | 2 | 2 | 3 | 3 | 1 | 1 | 2 | 2 | 3 | 3 |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* -- k -->
*
* If the number of DMRS CDM groups without data is set to:
* - 1, data is mapped in RE marked as 2 and 3
* - 2, data is mapped in RE marked as 3
* - otherwise, no data is mapped in this symbol
*/
static uint32_t srsran_pdsch_nr_cp_dmrs_type2(const srsran_pdsch_nr_t* q,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
static inline uint32_t pdsch_nr_get_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
{
uint32_t count = 0;
if (grant->nof_dmrs_cdm_groups_without_data != 1 && grant->nof_dmrs_cdm_groups_without_data != 2) {
return count;
}
uint32_t re_offset = (grant->nof_dmrs_cdm_groups_without_data == 1) ? 2 : 4;
uint32_t re_count = (grant->nof_dmrs_cdm_groups_without_data == 1) ? 4 : 2;
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
if (grant->prb_idx[i]) {
// Copy RE between pilot pairs
srsran_pdsch_re_cp(&sf_symbols[i * SRSRAN_NRE + re_offset], &symbols[count], re_count, put);
count += re_count;
// Copy RE after second pilot
srsran_pdsch_re_cp(&sf_symbols[(i + 1) * SRSRAN_NRE - re_count], &symbols[count], re_count, put);
count += re_count;
for (uint32_t i = 0; i < SRSRAN_NRE; i++) {
if (!rvd_mask[i]) {
dst[count++] = src[i];
}
}
return count;
}
static uint32_t srsran_pdsch_nr_cp_dmrs(const srsran_pdsch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
{
uint32_t count = 0;
const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs;
switch (dmrs_cfg->type) {
case srsran_dmrs_sch_type_1:
count = srsran_pdsch_nr_cp_dmrs_type1(q, grant, symbols, sf_symbols, put);
break;
case srsran_dmrs_sch_type_2:
count = srsran_pdsch_nr_cp_dmrs_type2(q, grant, symbols, sf_symbols, put);
break;
}
return count;
}
static uint32_t srsran_pdsch_nr_cp_clean(const srsran_pdsch_nr_t* q,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
{
uint32_t count = 0;
uint32_t start = 0; // Index of the start of continuous data
uint32_t length = 0; // End of continuous RE
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
if (grant->prb_idx[i]) {
// If fist continuous block, save start
if (length == 0) {
start = i * SRSRAN_NRE;
}
length += SRSRAN_NRE;
} else {
// Consecutive block is finished
if (put) {
srsran_vec_cf_copy(&sf_symbols[start], &symbols[count], length);
} else {
srsran_vec_cf_copy(&symbols[count], &sf_symbols[start], length);
}
// Increase RE count
count += length;
// Reset consecutive block
length = 0;
}
}
// Copy last contiguous block
if (length > 0) {
if (put) {
srsran_vec_cf_copy(&sf_symbols[start], &symbols[count], length);
} else {
srsran_vec_cf_copy(&symbols[count], &sf_symbols[start], length);
}
count += length;
}
return count;
}
@ -349,35 +204,40 @@ static int srsran_pdsch_nr_cp(const srsran_pdsch_nr_t* q,
cf_t* sf_symbols,
bool put)
{
uint32_t count = 0;
uint32_t dmrs_l_idx[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {};
uint32_t dmrs_l_count = 0;
uint32_t count = 0;
// Get symbol indexes carrying DMRS
int32_t nof_dmrs_symbols = srsran_dmrs_sch_get_symbols_idx(&cfg->dmrs, grant, dmrs_l_idx);
if (nof_dmrs_symbols < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
for (uint32_t l = grant->S; l < grant->S + grant->L; l++) {
// Initialise reserved RE mask to all false
bool rvd_mask[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {};
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("dmrs_l_idx=");
srsran_vec_fprint_i(stdout, (int32_t*)dmrs_l_idx, nof_dmrs_symbols);
}
// Reserve DMRS
if (srsran_re_pattern_to_symbol_mask(&q->dmrs_re_pattern, l, rvd_mask) < SRSRAN_SUCCESS) {
ERROR("Error generating DMRS reserved RE mask");
return SRSRAN_ERROR;
}
for (uint32_t l = grant->S; l < grant->S + grant->L; l++) {
// Advance DMRS symbol counter until:
// - the current DMRS symbol index is greater or equal than current symbol l
// - no more DMRS symbols
while (dmrs_l_idx[dmrs_l_count] < l && dmrs_l_count < nof_dmrs_symbols) {
dmrs_l_count++;
// Reserve RE from configuration
if (srsran_re_pattern_list_to_symbol_mask(&cfg->rvd_re, l, rvd_mask) < SRSRAN_SUCCESS) {
ERROR("Error generating reserved RE mask");
return SRSRAN_ERROR;
}
if (l == dmrs_l_idx[dmrs_l_count]) {
count += srsran_pdsch_nr_cp_dmrs(
q, cfg, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSRAN_NRE], put);
} else {
count +=
srsran_pdsch_nr_cp_clean(q, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSRAN_NRE], put);
// Actual copy
for (uint32_t rb = 0; rb < q->carrier.nof_prb; rb++) {
// Skip PRB if not available in grant
if (!grant->prb_idx[rb]) {
continue;
}
// Calculate RE index at the begin of the symbol
uint32_t re_idx = (q->carrier.nof_prb * l + rb) * SRSRAN_NRE;
// Put or get
if (put) {
count += pdsch_nr_put_rb(&sf_symbols[re_idx], &symbols[count], &rvd_mask[rb * SRSRAN_NRE]);
} else {
count += pdsch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]);
}
}
}
@ -487,6 +347,12 @@ int srsran_pdsch_nr_encode(srsran_pdsch_nr_t* q,
return SRSRAN_ERROR;
}
// Compute DMRS pattern
if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) {
ERROR("Error computing DMRS pattern");
return SRSRAN_ERROR;
}
// 7.3.1.1 and 7.3.1.2
uint32_t nof_cw = 0;
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
@ -571,10 +437,8 @@ static inline int pdsch_nr_decode_codeword(srsran_pdsch_nr_t* q,
res->evm = srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
}
// Change LLR sign
for (uint32_t i = 0; i < tb->nof_bits; i++) {
llr[i] = -llr[i];
}
// Change LLR sign and set to zero the LLR that are not used
srsran_vec_neg_bb(llr, llr, tb->nof_bits);
// Descrambling
srsran_sequence_apply_c(llr, llr, tb->nof_bits, pdsch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx));
@ -610,12 +474,18 @@ int srsran_pdsch_nr_decode(srsran_pdsch_nr_t* q,
gettimeofday(&t[1], NULL);
}
// Compute DMRS pattern
if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) {
ERROR("Error computing DMRS pattern");
return SRSRAN_ERROR;
}
uint32_t nof_cw = 0;
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
nof_cw += grant->tb[tb].enabled ? 1 : 0;
}
uint32_t nof_re = srsran_ra_dl_nr_slot_nof_re(cfg, grant);
uint32_t nof_re = grant->tb[0].nof_re;
if (channel->nof_re != nof_re) {
ERROR("Inconsistent number of RE (%d!=%d)", channel->nof_re, nof_re);
@ -723,6 +593,12 @@ uint32_t srsran_pdsch_nr_rx_info(const srsran_pdsch_nr_t* q,
len += srsran_pdsch_nr_grant_info(cfg, grant, &str[len], str_len - len);
if (cfg->rvd_re.count != 0) {
len = srsran_print_check(str, str_len, len, ", Reserved={");
len += srsran_re_pattern_list_info(&cfg->rvd_re, &str[len], str_len - len);
len = srsran_print_check(str, str_len, len, "}");
}
if (q->evm_buffer != NULL) {
len = srsran_print_check(str, str_len, len, ",evm={", 0);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
@ -766,13 +642,5 @@ uint32_t srsran_pdsch_nr_tx_info(const srsran_pdsch_nr_t* q,
char* str,
uint32_t str_len)
{
uint32_t len = 0;
len += srsran_pdsch_nr_grant_info(cfg, grant, &str[len], str_len - len);
if (q->meas_time_en) {
len = srsran_print_check(str, str_len, len, ", t=%d us", q->meas_time_us);
}
return len;
return srsran_pdsch_nr_rx_info(q, cfg, grant, NULL, str, str_len);
}

@ -11,6 +11,7 @@
*/
#include "srsran/phy/phch/ra_nr.h"
#include "srsran/phy/ch_estimation/csi_rs.h"
#include "srsran/phy/phch/csi.h"
#include "srsran/phy/phch/pdsch_nr.h"
#include "srsran/phy/phch/ra_dl_nr.h"
@ -245,6 +246,27 @@ static ra_nr_table_t ra_nr_select_table(srsran_mcs_table_t mcs_table,
return ra_nr_select_table_pdsch(mcs_table, dci_format, search_space_type, rnti_type);
}
static int ra_nr_dmrs_power_offset(srsran_sch_grant_nr_t* grant)
{
if (grant == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Defined by TS 38.214 V15.10.0:
// - Table 4.1-1: The ratio of PDSCH EPRE to DM-RS EPRE
// - Table 6.2.2-1: The ratio of PUSCH EPRE to DM-RS EPRE
float ratio_dB[3] = {0, -3, -4.77};
if (grant->nof_dmrs_cdm_groups_without_data < 1 || grant->nof_dmrs_cdm_groups_without_data > 3) {
ERROR("Invalid number of DMRS CDM groups without data (%d)", grant->nof_dmrs_cdm_groups_without_data);
return SRSRAN_ERROR;
}
grant->beta_dmrs = srsran_convert_dB_to_amplitude(-ratio_dB[grant->nof_dmrs_cdm_groups_without_data - 1]);
return SRSRAN_SUCCESS;
}
double srsran_ra_nr_R_from_mcs(srsran_mcs_table_t mcs_table,
srsran_dci_format_nr_t dci_format,
srsran_search_space_type_t search_space_type,
@ -405,6 +427,34 @@ uint32_t srsran_ra_nr_tbs(uint32_t N_re, double S, double R, uint32_t Qm, uint32
return ra_nr_tbs_from_n_info4(n_info, R);
}
static int ra_nr_assert_csi_rs_dmrs_collision(const srsran_sch_cfg_nr_t* pdsch_cfg)
{
// Generate DMRS pattern
srsran_re_pattern_t dmrs_re_pattern = {};
if (srsran_dmrs_sch_rvd_re_pattern(&pdsch_cfg->dmrs, &pdsch_cfg->grant, &dmrs_re_pattern) < SRSRAN_SUCCESS) {
ERROR("Error computing DMRS pattern");
return SRSRAN_ERROR;
}
// Check for collision
if (srsran_re_pattern_check_collision(&pdsch_cfg->rvd_re, &dmrs_re_pattern) < SRSRAN_SUCCESS) {
// Create reserved info string
char str_rvd[512] = {};
srsran_re_pattern_list_info(&pdsch_cfg->rvd_re, str_rvd, (uint32_t)sizeof(str_rvd));
// Create DMRS info string
char str_dmrs[512] = {};
srsran_re_pattern_info(&dmrs_re_pattern, str_dmrs, (uint32_t)sizeof(str_dmrs));
ERROR("Error. The UE is not expected to receive CSI-RS (%s) and DM-RS (%s) on the same resource elements.",
str_rvd,
str_dmrs);
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg,
const srsran_sch_grant_nr_t* grant,
uint32_t mcs_idx,
@ -451,7 +501,7 @@ int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg,
// 1) The UE shall first determine the number of REs (N RE ) within the slot.
int N_re = srsran_ra_dl_nr_slot_nof_re(pdsch_cfg, grant);
if (N_re <= SRSRAN_SUCCESS) {
ERROR("Invalid number of RE");
ERROR("Invalid number of RE (%d)", N_re);
return SRSRAN_ERROR;
}
@ -461,55 +511,141 @@ int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg,
uint32_t nof_layers_cw2 = grant->nof_layers - nof_layers_cw1;
tb->N_L = (cw_idx == 0) ? nof_layers_cw1 : nof_layers_cw2;
// Check DMRS and CSI-RS collision according to TS 38.211 7.4.1.5.3 Mapping to physical resources
// If there was a collision, the number of RE in the grant would be wrong
if (ra_nr_assert_csi_rs_dmrs_collision(pdsch_cfg) < SRSRAN_SUCCESS) {
ERROR("Error: CSI-RS and DMRS collision detected");
return SRSRAN_ERROR;
}
// Calculate reserved RE
uint32_t N_re_rvd = srsran_re_pattern_list_count(&pdsch_cfg->rvd_re, grant->S, grant->S + grant->L, grant->prb_idx);
// Steps 2,3,4
tb->tbs = (int)srsran_ra_nr_tbs(N_re, S, R, Qm, tb->N_L);
tb->R = R;
tb->mod = m;
tb->nof_re = N_re * grant->nof_layers;
tb->nof_re = (N_re - N_re_rvd) * grant->nof_layers;
tb->nof_bits = tb->nof_re * Qm;
tb->enabled = true;
return SRSRAN_SUCCESS;
}
static int ra_dl_dmrs(const srsran_sch_hl_cfg_nr_t* pdsch_hl_cfg,
srsran_sch_grant_nr_t* pdsch_grant,
srsran_dmrs_sch_cfg_t* dmrs_cfg)
static int ra_dl_dmrs(const srsran_sch_hl_cfg_nr_t* hl_cfg, srsran_sch_grant_nr_t* grant, srsran_sch_cfg_nr_t* cfg)
{
const bool dedicated_dmrs_present = (pdsch_grant->mapping == srsran_sch_mapping_type_A)
? pdsch_hl_cfg->dmrs_typeA.present
: pdsch_hl_cfg->dmrs_typeB.present;
const bool dedicated_dmrs_present =
(grant->mapping == srsran_sch_mapping_type_A) ? hl_cfg->dmrs_typeA.present : hl_cfg->dmrs_typeB.present;
if (pdsch_grant->dci_format == srsran_dci_format_nr_1_0 || !dedicated_dmrs_present) {
if (pdsch_grant->mapping == srsran_sch_mapping_type_A) {
if (grant->dci_format == srsran_dci_format_nr_1_0 || !dedicated_dmrs_present) {
if (grant->mapping == srsran_sch_mapping_type_A) {
// Absent default values are defined is TS 38.331 - DMRS-DownlinkConfig
dmrs_cfg->additional_pos = srsran_dmrs_sch_add_pos_2;
dmrs_cfg->type = srsran_dmrs_sch_type_1;
dmrs_cfg->length = srsran_dmrs_sch_len_1;
dmrs_cfg->scrambling_id0_present = false;
dmrs_cfg->scrambling_id1_present = false;
if (pdsch_grant->dci_format == srsran_dci_format_nr_1_0) {
if (srsran_ra_dl_nr_nof_dmrs_cdm_groups_without_data_format_1_0(dmrs_cfg, pdsch_grant) < SRSRAN_SUCCESS) {
ERROR("Error loading number of DMRS CDM groups");
return SRSRAN_ERROR;
}
} else {
ERROR("Invalid case");
return SRSRAN_ERROR;
}
cfg->dmrs.additional_pos = srsran_dmrs_sch_add_pos_2;
cfg->dmrs.type = srsran_dmrs_sch_type_1;
cfg->dmrs.length = srsran_dmrs_sch_len_1;
cfg->dmrs.scrambling_id0_present = false;
cfg->dmrs.scrambling_id1_present = false;
} else {
ERROR("Unsupported configuration");
return SRSRAN_ERROR;
}
} else {
if (grant->mapping == srsran_sch_mapping_type_A) {
cfg->dmrs.additional_pos = hl_cfg->dmrs_typeA.additional_pos;
cfg->dmrs.type = hl_cfg->dmrs_typeA.type;
cfg->dmrs.length = hl_cfg->dmrs_typeA.length;
cfg->dmrs.scrambling_id0_present = false;
cfg->dmrs.scrambling_id1_present = false;
} else {
cfg->dmrs.additional_pos = hl_cfg->dmrs_typeB.additional_pos;
cfg->dmrs.type = hl_cfg->dmrs_typeB.type;
cfg->dmrs.length = hl_cfg->dmrs_typeB.length;
cfg->dmrs.scrambling_id0_present = false;
cfg->dmrs.scrambling_id1_present = false;
}
}
return SRSRAN_SUCCESS;
// Set number of DMRS CDM groups without data
if (grant->dci_format == srsran_dci_format_nr_1_0) {
if (srsran_ra_dl_nr_nof_dmrs_cdm_groups_without_data_format_1_0(&cfg->dmrs, grant) < SRSRAN_SUCCESS) {
ERROR("Error loading number of DMRS CDM groups");
return SRSRAN_ERROR;
}
} else {
ERROR("Invalid case");
return SRSRAN_ERROR;
}
ERROR("Unsupported configuration");
// Set DMRS power offset Table 6.2.2-1: The ratio of PUSCH EPRE to DM-RS EPRE
if (ra_nr_dmrs_power_offset(grant) < SRSRAN_SUCCESS) {
ERROR("Error setting DMRS power offset");
return SRSRAN_ERROR;
}
return SRSRAN_ERROR;
return SRSRAN_SUCCESS;
}
static int ra_dl_resource_mapping(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot,
const srsran_sch_hl_cfg_nr_t* pdsch_hl_cfg,
srsran_sch_cfg_nr_t* pdsch_cfg)
{
// SS/PBCH block transmission resources not available for PDSCH
// ... Not implemented
// 5.1.4.1 PDSCH resource mapping with RB symbol level granularity
// rateMatchPatternToAddModList ... Not implemented
// 5.1.4.2 PDSCH resource mapping with RE level granularity
// RateMatchingPatternLTE-CRS ... Not implemented
// Append periodic ZP-CSI-RS
for (uint32_t i = 0; i < pdsch_hl_cfg->p_zp_csi_rs_set.count; i++) {
// Select resource
const srsran_csi_rs_zp_resource_t* resource = &pdsch_hl_cfg->p_zp_csi_rs_set.data[i];
// Check if the periodic ZP-CSI is transmitted
if (srsran_csi_rs_send(&resource->periodicity, slot)) {
INFO("Tx/Rx ZP-CSI-RS @slot=%d\n", slot->idx);
if (srsran_csi_rs_append_resource_to_pattern(carrier, &resource->resource_mapping, &pdsch_cfg->rvd_re)) {
ERROR("Error appending ZP-CSI-RS as RE pattern");
return SRSRAN_ERROR;
}
}
}
// Append semi-persistent ZP-CSI-RS here
// ... not implemented
// Append aperiodic ZP-CSI-RS here
// ... not implemented
// Append periodic NZP-CSI-RS according to TS 38.211 clause 7.3.1.5 Mapping to virtual resource blocks
// Only aplicable if CRC is scrambled by C-RNTI, MCS-C-RNTI, CS-RNTI, or PDSCH with SPS
bool nzp_rvd_valid = pdsch_cfg->grant.rnti_type == srsran_rnti_type_c ||
pdsch_cfg->grant.rnti_type == srsran_rnti_type_mcs_c ||
pdsch_cfg->grant.rnti_type == srsran_rnti_type_cs;
for (uint32_t set_id = 0; set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS && nzp_rvd_valid; set_id++) {
for (uint32_t res_id = 0; res_id < pdsch_hl_cfg->nzp_csi_rs_sets[set_id].count; res_id++) {
// Select resource
const srsran_csi_rs_nzp_resource_t* resource = &pdsch_hl_cfg->nzp_csi_rs_sets[set_id].data[res_id];
// Check if the periodic ZP-CSI is transmitted
if (srsran_csi_rs_send(&resource->periodicity, slot)) {
INFO("Tx/Rx NZP-CSI-RS set_id=%d; res=%d; @slot=%d\n", set_id, res_id, slot->idx);
if (srsran_csi_rs_append_resource_to_pattern(carrier, &resource->resource_mapping, &pdsch_cfg->rvd_re)) {
ERROR("Error appending ZP-CSI-RS as RE pattern");
return SRSRAN_ERROR;
}
}
}
}
return SRSRAN_SUCCESS;
}
int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot,
const srsran_sch_hl_cfg_nr_t* pdsch_hl_cfg,
const srsran_dci_dl_nr_t* dci_dl,
srsran_sch_cfg_nr_t* pdsch_cfg,
@ -541,8 +677,14 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
pdsch_grant->rnti_type = dci_dl->rnti_type;
pdsch_grant->tb[0].rv = dci_dl->rv;
// 5.1.4 PDSCH resource mapping
if (ra_dl_resource_mapping(carrier, slot, pdsch_hl_cfg, pdsch_cfg) < SRSRAN_SUCCESS) {
ERROR("Error in resource mapping");
return SRSRAN_ERROR;
}
// 5.1.6.2 DM-RS reception procedure
if (ra_dl_dmrs(pdsch_hl_cfg, pdsch_grant, &pdsch_cfg->dmrs) < SRSRAN_SUCCESS) {
if (ra_dl_dmrs(pdsch_hl_cfg, pdsch_grant, pdsch_cfg) < SRSRAN_SUCCESS) {
ERROR("Error selecting DMRS configuration");
return SRSRAN_ERROR;
}
@ -603,7 +745,7 @@ ra_ul_dmrs(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, srsran_sch_grant_nr_t* pu
}
// Set DMRS power offset Table 6.2.2-1: The ratio of PUSCH EPRE to DM-RS EPRE
if (srsran_ra_ul_nr_dmrs_power_offset(pusch_grant) < SRSRAN_SUCCESS) {
if (ra_nr_dmrs_power_offset(pusch_grant) < SRSRAN_SUCCESS) {
ERROR("Error setting DMRS power offset");
return SRSRAN_ERROR;
}
@ -746,4 +888,4 @@ int srsran_ra_ul_set_grant_uci_nr(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg,
pusch_cfg->uci = *uci_cfg;
return SRSRAN_SUCCESS;
}
}

@ -222,24 +222,6 @@ int srsran_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(const srsran_sch
return SRSRAN_SUCCESS;
}
int srsran_ra_ul_nr_dmrs_power_offset(srsran_sch_grant_nr_t* grant)
{
if (grant == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
float ratio_dB[3] = {0, -3, -4.77};
if (grant->nof_dmrs_cdm_groups_without_data < 1 || grant->nof_dmrs_cdm_groups_without_data > 3) {
ERROR("Invalid number of DMRS CDM groups without data (%d)", grant->nof_dmrs_cdm_groups_without_data);
return SRSRAN_ERROR;
}
grant->beta_dmrs = srsran_convert_dB_to_amplitude(-ratio_dB[grant->nof_dmrs_cdm_groups_without_data - 1]);
return SRSRAN_SUCCESS;
}
#define RA_UL_PUCCH_CODE_RATE_N 8
#define RA_UL_PUCCH_CODE_RATE_RESERVED NAN

@ -28,11 +28,10 @@ static srsran_carrier_nr_t carrier = {
1 // max_mimo_layers
};
static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering
static srsran_sch_cfg_nr_t pdsch_cfg = {};
static srsran_sch_grant_nr_t pdsch_grant = {};
static uint16_t rnti = 0x1234;
static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering
static srsran_sch_cfg_nr_t pdsch_cfg = {};
static uint16_t rnti = 0x1234;
void usage(char* prog)
{
@ -153,20 +152,20 @@ int main(int argc, char** argv)
}
// Use grant default A time resources with m=0
if (srsran_ra_dl_nr_time_default_A(0, pdsch_cfg.dmrs.typeA_pos, &pdsch_grant) < SRSRAN_SUCCESS) {
if (srsran_ra_dl_nr_time_default_A(0, pdsch_cfg.dmrs.typeA_pos, &pdsch_cfg.grant) < SRSRAN_SUCCESS) {
ERROR("Error loading default grant");
goto clean_exit;
}
// Load number of DMRS CDM groups without data
if (srsran_ra_dl_nr_nof_dmrs_cdm_groups_without_data_format_1_0(&pdsch_cfg.dmrs, &pdsch_grant) < SRSRAN_SUCCESS) {
if (srsran_ra_dl_nr_nof_dmrs_cdm_groups_without_data_format_1_0(&pdsch_cfg.dmrs, &pdsch_cfg.grant) < SRSRAN_SUCCESS) {
ERROR("Error loading number of DMRS CDM groups without data");
goto clean_exit;
}
pdsch_grant.nof_layers = carrier.max_mimo_layers;
pdsch_grant.dci_format = srsran_dci_format_nr_1_0;
pdsch_grant.rnti = rnti;
pdsch_cfg.grant.nof_layers = carrier.max_mimo_layers;
pdsch_cfg.grant.dci_format = srsran_dci_format_nr_1_0;
pdsch_cfg.grant.rnti = rnti;
uint32_t n_prb_start = 1;
uint32_t n_prb_end = carrier.nof_prb + 1;
@ -190,10 +189,10 @@ int main(int argc, char** argv)
for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) {
for (mcs = mcs_start; mcs < mcs_end; mcs++) {
for (uint32_t n = 0; n < SRSRAN_MAX_PRB_NR; n++) {
pdsch_grant.prb_idx[n] = (n < n_prb);
pdsch_cfg.grant.prb_idx[n] = (n < n_prb);
}
if (srsran_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &pdsch_grant.tb[0]) < SRSRAN_SUCCESS) {
if (srsran_ra_nr_fill_tb(&pdsch_cfg, &pdsch_cfg.grant, mcs, &pdsch_cfg.grant.tb[0]) < SRSRAN_SUCCESS) {
ERROR("Error filing tb");
goto clean_exit;
}
@ -204,28 +203,29 @@ int main(int argc, char** argv)
continue;
}
for (uint32_t i = 0; i < pdsch_grant.tb[tb].tbs; i++) {
for (uint32_t i = 0; i < pdsch_cfg.grant.tb[tb].tbs; i++) {
data_tx[tb][i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, UINT8_MAX);
}
pdsch_grant.tb[tb].softbuffer.tx = &softbuffer_tx;
pdsch_cfg.grant.tb[tb].softbuffer.tx = &softbuffer_tx;
}
if (srsran_pdsch_nr_encode(&pdsch_tx, &pdsch_cfg, &pdsch_grant, data_tx, sf_symbols) < SRSRAN_SUCCESS) {
if (srsran_pdsch_nr_encode(&pdsch_tx, &pdsch_cfg, &pdsch_cfg.grant, data_tx, sf_symbols) < SRSRAN_SUCCESS) {
ERROR("Error encoding");
goto clean_exit;
}
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx;
srsran_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx);
pdsch_cfg.grant.tb[tb].softbuffer.rx = &softbuffer_rx;
srsran_softbuffer_rx_reset(pdsch_cfg.grant.tb[tb].softbuffer.rx);
}
for (uint32_t i = 0; i < pdsch_grant.tb->nof_re; i++) {
for (uint32_t i = 0; i < pdsch_cfg.grant.tb->nof_re; i++) {
chest.ce[0][0][i] = 1.0f;
}
chest.nof_re = pdsch_grant.tb->nof_re;
chest.nof_re = pdsch_cfg.grant.tb->nof_re;
if (srsran_pdsch_nr_decode(&pdsch_rx, &pdsch_cfg, &pdsch_grant, &chest, sf_symbols, pdsch_res) < SRSRAN_SUCCESS) {
if (srsran_pdsch_nr_decode(&pdsch_rx, &pdsch_cfg, &pdsch_cfg.grant, &chest, sf_symbols, pdsch_res) <
SRSRAN_SUCCESS) {
ERROR("Error encoding");
goto clean_exit;
}
@ -236,18 +236,18 @@ int main(int argc, char** argv)
}
float mse = 0.0f;
uint32_t nof_re = srsran_ra_dl_nr_slot_nof_re(&pdsch_cfg, &pdsch_grant);
for (uint32_t i = 0; i < pdsch_grant.nof_layers; i++) {
uint32_t nof_re = srsran_ra_dl_nr_slot_nof_re(&pdsch_cfg, &pdsch_cfg.grant);
for (uint32_t i = 0; i < pdsch_cfg.grant.nof_layers; i++) {
for (uint32_t j = 0; j < nof_re; j++) {
mse += cabsf(pdsch_tx.d[i][j] - pdsch_rx.d[i][j]);
}
}
if (nof_re * pdsch_grant.nof_layers > 0) {
mse = mse / (nof_re * pdsch_grant.nof_layers);
if (nof_re * pdsch_cfg.grant.nof_layers > 0) {
mse = mse / (nof_re * pdsch_cfg.grant.nof_layers);
}
if (mse > 0.001) {
ERROR("MSE error (%f) is too high", mse);
for (uint32_t i = 0; i < pdsch_grant.nof_layers; i++) {
for (uint32_t i = 0; i < pdsch_cfg.grant.nof_layers; i++) {
printf("d_tx[%d]=", i);
srsran_vec_fprint_c(stdout, pdsch_tx.d[i], nof_re);
printf("d_rx[%d]=", i);
@ -257,20 +257,20 @@ int main(int argc, char** argv)
}
if (!pdsch_res[0].crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_grant.tb[0].tbs);
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs);
goto clean_exit;
}
if (memcmp(data_tx[0], data_rx[0], pdsch_grant.tb[0].tbs / 8) != 0) {
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_grant.tb[0].tbs);
if (memcmp(data_tx[0], data_rx[0], pdsch_cfg.grant.tb[0].tbs / 8) != 0) {
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs);
printf("Tx data: ");
srsran_vec_fprint_byte(stdout, data_tx[0], pdsch_grant.tb[0].tbs / 8);
srsran_vec_fprint_byte(stdout, data_tx[0], pdsch_cfg.grant.tb[0].tbs / 8);
printf("Rx data: ");
srsran_vec_fprint_byte(stdout, data_rx[0], pdsch_grant.tb[0].tbs / 8);
srsran_vec_fprint_byte(stdout, data_rx[0], pdsch_cfg.grant.tb[0].tbs / 8);
goto clean_exit;
}
printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_grant.tb[0].tbs, pdsch_res[0].evm);
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res[0].evm);
}
}

@ -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;
}

@ -36,10 +36,19 @@ target_link_libraries(vector_test srsran_phy)
add_test(vector_test vector_test)
########################################################################
# Ring-Buffer TEST
########################################################################
add_executable(ringbuffer_test ring_buffer_test.c)
target_link_libraries(ringbuffer_test srsran_phy)
add_test(ringbuffer_tester ringbuffer_test)
########################################################################
# RE-Pattern TEST
########################################################################
add_executable(re_pattern_test re_pattern_test.c)
target_link_libraries(re_pattern_test srsran_phy)
add_test(re_pattern_test re_pattern_test)

@ -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;
}

@ -211,6 +211,44 @@ TEST(
free(y);
free(z);)
TEST(
srsran_vec_neg_bbb, MALLOC(int8_t, x); MALLOC(int8_t, y); MALLOC(int8_t, z);
int16_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_B();
do {
y[i] = RANDOM_B();
} while (!y[i]);
}
TEST_CALL(srsran_vec_neg_bbb(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = y[i] < 0 ? -x[i] : x[i];
mse += abs(gold - z[i]);
}
free(x);
free(y);
free(z);)
TEST(
srsran_vec_neg_bb, MALLOC(int8_t, x); MALLOC(int8_t, z);
int16_t gold = 0.0f;
for (int i = 0; i < block_size; i++) { x[i] = RANDOM_B(); }
TEST_CALL(srsran_vec_neg_bb(x, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = -x[i];
mse += abs(gold - z[i]);
}
free(x);
free(z);)
TEST(
srsran_vec_acc_cc, MALLOC(cf_t, x); cf_t z = 0.0f;
@ -836,6 +874,14 @@ int main(int argc, char** argv)
test_srsran_vec_neg_sss(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] =
test_srsran_vec_neg_bbb(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] =
test_srsran_vec_neg_bb(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] =
test_srsran_vec_acc_cc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;

@ -465,11 +465,19 @@ void srsran_vec_neg_sss(const int16_t* x, const int16_t* y, int16_t* z, const ui
{
srsran_vec_neg_sss_simd(x, y, z, len);
}
void srsran_vec_neg_bbb(const int8_t* x, const int8_t* y, int8_t* z, const uint32_t len)
{
srsran_vec_neg_bbb_simd(x, y, z, len);
}
void srsran_vec_neg_bb(const int8_t* x, int8_t* z, const uint32_t len)
{
for (uint32_t i = 0; i < len; i++) {
z[i] = -x[i];
}
}
// CFO and OFDM processing
void srsran_vec_prod_ccc(const cf_t* x, const cf_t* y, cf_t* z, const uint32_t len)
{

@ -2,7 +2,7 @@
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
* 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

@ -1,5 +1,5 @@
#
# Copyright 2013-2021 Software Radio Systems Limited
# Copyright 2013-2020 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
@ -52,4 +52,7 @@ add_lte_test(pucch_ca_test pucch_ca_test)
add_executable(phy_dl_nr_test phy_dl_nr_test.c)
target_link_libraries(phy_dl_nr_test srsran_phy srsran_common srsran_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_nr_test(phy_dl_nr_test phy_dl_nr_test -p 100 -m 28)
add_nr_test(phy_dl_nr_test phy_dl_nr_test -p 100 -m 28)
add_nr_test(phy_dl_nr_test_rvd phy_dl_nr_test -P 52 -p 52 -m 0
-R 0 52 1 010010010010 00000000010000
-R 0 52 1 100100100100 00000010000000)

@ -20,20 +20,18 @@
#include <getopt.h>
static srsran_carrier_nr_t carrier = {
0, // cell_id
501, // cell_id
0, // numerology
100, // nof_prb
52, // nof_prb
0, // start
1 // max_mimo_layers
};
static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering
static srsran_sch_cfg_nr_t pdsch_cfg = {};
static srsran_sch_grant_nr_t pdsch_grant = {};
static uint16_t rnti = 0x1234;
static uint32_t nof_slots = 10;
static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering
static srsran_sch_cfg_nr_t pdsch_cfg = {};
static uint32_t nof_slots = 10;
static void usage(char* prog)
{
@ -44,6 +42,7 @@ static void usage(char* prog)
printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs);
printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
srsran_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table));
printf("\t-R Reserve RE: [rb_begin] [rb_end] [rb_stride] [sc_mask] [symbol_mask]\n");
printf("\t-L Provide number of layers [Default %d]\n", carrier.max_mimo_layers);
printf("\t-v [set srsran_verbose to debug, default none]\n");
}
@ -51,7 +50,7 @@ static void usage(char* prog)
static int parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "PpmnTLv")) != -1) {
while ((opt = getopt(argc, argv, "RPpmnTLv")) != -1) {
switch (opt) {
case 'P':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
@ -68,6 +67,24 @@ static int parse_args(int argc, char** argv)
case 'T':
pdsch_cfg.sch_cfg.mcs_table = srsran_mcs_table_from_str(argv[optind]);
break;
case 'R': {
srsran_re_pattern_t pattern = {};
pattern.rb_begin = (uint32_t)strtol(argv[optind++], NULL, 10);
pattern.rb_end = (uint32_t)strtol(argv[optind++], NULL, 10);
pattern.rb_stride = (uint32_t)strtol(argv[optind++], NULL, 10);
uint32_t sc_mask = (uint32_t)strtol(argv[optind++], NULL, 2);
for (uint32_t i = 0; i < SRSRAN_NRE; i++) {
pattern.sc[i] = ((sc_mask >> (SRSRAN_NRE - 1U - i)) & 0x1) == 0x1;
}
uint32_t symbol_mask = (uint32_t)strtol(argv[optind], NULL, 2);
for (uint32_t i = 0; i < SRSRAN_NSYMB_PER_SLOT_NR; i++) {
pattern.symbol[i] = ((symbol_mask >> (SRSRAN_NSYMB_PER_SLOT_NR - 1U - i)) & 0x1) == 0x1;
}
if (srsran_re_pattern_merge(&pdsch_cfg.rvd_re, &pattern) < SRSRAN_ERROR) {
ERROR("Error adding pattern");
return SRSRAN_ERROR;
}
} break;
case 'L':
carrier.max_mimo_layers = (uint32_t)strtol(argv[optind], NULL, 10);
break;
@ -86,7 +103,6 @@ static int parse_args(int argc, char** argv)
static int work_gnb_dl(srsran_enb_dl_nr_t* enb_dl,
srsran_slot_cfg_t* slot,
srsran_search_space_t* search_space,
srsran_dci_dl_nr_t* dci_dl,
srsran_dci_location_t* dci_location,
uint8_t** data_tx)
{
@ -96,20 +112,26 @@ static int work_gnb_dl(srsran_enb_dl_nr_t* enb_dl,
}
// Hard-coded values
dci_dl->format = srsran_dci_format_nr_1_0;
dci_dl->rnti_type = srsran_rnti_type_c;
dci_dl->location = *dci_location;
dci_dl->search_space = search_space->type;
dci_dl->rnti = rnti;
srsran_dci_dl_nr_t dci_dl = {};
dci_dl.rnti = pdsch_cfg.grant.rnti;
dci_dl.rnti_type = pdsch_cfg.grant.rnti_type;
dci_dl.format = srsran_dci_format_nr_1_0;
dci_dl.location = *dci_location;
dci_dl.search_space = search_space->type;
dci_dl.coreset_id = 1;
dci_dl.freq_domain_assigment = 0;
dci_dl.time_domain_assigment = 0;
dci_dl.vrb_to_prb_mapping = 0;
dci_dl.mcs = mcs;
dci_dl.rv = 0;
// Put actual DCI
if (srsran_enb_dl_nr_pdcch_put(enb_dl, slot, dci_dl) < SRSRAN_SUCCESS) {
if (srsran_enb_dl_nr_pdcch_put(enb_dl, slot, &dci_dl) < SRSRAN_SUCCESS) {
ERROR("Error putting PDCCH");
return SRSRAN_ERROR;
}
// Put PDSCH transmission
pdsch_cfg.grant = pdsch_grant;
if (srsran_enb_dl_nr_pdsch_put(enb_dl, slot, &pdsch_cfg, data_tx) < SRSRAN_SUCCESS) {
ERROR("Error putting PDSCH");
return SRSRAN_ERROR;
@ -124,8 +146,9 @@ static int work_ue_dl(srsran_ue_dl_nr_t* ue_dl, srsran_slot_cfg_t* slot, srsran_
{
srsran_ue_dl_nr_estimate_fft(ue_dl, slot);
srsran_dci_dl_nr_t dci_dl_rx = {};
int nof_found_dci = srsran_ue_dl_nr_find_dl_dci(ue_dl, slot, rnti, srsran_rnti_type_c, &dci_dl_rx, 1);
srsran_dci_dl_nr_t dci_dl_rx = {};
int nof_found_dci =
srsran_ue_dl_nr_find_dl_dci(ue_dl, slot, pdsch_cfg.grant.rnti, pdsch_cfg.grant.rnti_type, &dci_dl_rx, 1);
if (nof_found_dci < SRSRAN_SUCCESS) {
ERROR("Error decoding");
return SRSRAN_ERROR;
@ -136,7 +159,6 @@ static int work_ue_dl(srsran_ue_dl_nr_t* ue_dl, srsran_slot_cfg_t* slot, srsran_
return SRSRAN_ERROR;
}
pdsch_cfg.grant = pdsch_grant;
if (srsran_ue_dl_nr_decode_pdsch(ue_dl, slot, &pdsch_cfg, pdsch_res) < SRSRAN_SUCCESS) {
ERROR("Error decoding");
return SRSRAN_ERROR;
@ -192,8 +214,8 @@ int main(int argc, char** argv)
srsran_ue_dl_nr_pdcch_cfg_t pdcch_cfg = {};
// Configure CORESET
srsran_coreset_t* coreset = &pdcch_cfg.coreset[0];
pdcch_cfg.coreset_present[0] = true;
srsran_coreset_t* coreset = &pdcch_cfg.coreset[1];
pdcch_cfg.coreset_present[1] = true;
coreset->duration = 2;
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
coreset->freq_resources[i] = i < carrier.nof_prb / 6;
@ -202,7 +224,9 @@ int main(int argc, char** argv)
// Configure Search Space
srsran_search_space_t* search_space = &pdcch_cfg.search_space[0];
pdcch_cfg.search_space_present[0] = true;
search_space->type = srsran_search_space_type_ue;
search_space->id = 0;
search_space->coreset_id = 1;
search_space->type = srsran_search_space_type_common_3;
for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) {
search_space->nof_candidates[L] = srsran_pdcch_nr_max_candidates_coreset(coreset, L);
}
@ -264,13 +288,16 @@ int main(int argc, char** argv)
}
// Use grant default A time resources with m=0
if (srsran_ra_dl_nr_time_default_A(0, pdsch_cfg.dmrs.typeA_pos, &pdsch_grant) < SRSRAN_SUCCESS) {
pdsch_cfg.dmrs.typeA_pos = srsran_dmrs_sch_typeA_pos_2;
if (srsran_ra_dl_nr_time_default_A(0, pdsch_cfg.dmrs.typeA_pos, &pdsch_cfg.grant) < SRSRAN_SUCCESS) {
ERROR("Error loading default grant");
goto clean_exit;
}
pdsch_grant.nof_layers = carrier.max_mimo_layers;
pdsch_grant.dci_format = srsran_dci_format_nr_1_0;
pdsch_grant.nof_dmrs_cdm_groups_without_data = 1;
pdsch_cfg.grant.nof_layers = carrier.max_mimo_layers;
pdsch_cfg.grant.dci_format = srsran_dci_format_nr_1_0;
pdsch_cfg.grant.nof_dmrs_cdm_groups_without_data = 1;
pdsch_cfg.grant.rnti_type = srsran_rnti_type_c;
pdsch_cfg.grant.rnti = 0x4601;
uint32_t n_prb_start = 1;
uint32_t n_prb_end = carrier.nof_prb + 1;
@ -291,10 +318,11 @@ int main(int argc, char** argv)
for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) {
for (mcs = mcs_start; mcs < mcs_end; mcs++, slot_count++) {
for (uint32_t n = 0; n < SRSRAN_MAX_PRB_NR; n++) {
pdsch_grant.prb_idx[n] = (n < n_prb);
pdsch_cfg.grant.prb_idx[n] = (n < n_prb);
}
pdsch_cfg.grant.nof_prb = n_prb;
if (srsran_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &pdsch_grant.tb[0]) < SRSRAN_SUCCESS) {
if (srsran_ra_nr_fill_tb(&pdsch_cfg, &pdsch_cfg.grant, mcs, &pdsch_cfg.grant.tb[0]) < SRSRAN_SUCCESS) {
ERROR("Error filing tb");
goto clean_exit;
}
@ -305,17 +333,17 @@ int main(int argc, char** argv)
continue;
}
for (uint32_t i = 0; i < pdsch_grant.tb[tb].tbs; i++) {
for (uint32_t i = 0; i < pdsch_cfg.grant.tb[tb].tbs; i++) {
data_tx[tb][i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, UINT8_MAX);
}
pdsch_grant.tb[tb].softbuffer.tx = &softbuffer_tx;
pdsch_cfg.grant.tb[tb].softbuffer.tx = &softbuffer_tx;
}
// Compute PDCCH candidate locations
uint32_t L = 0;
uint32_t ncce_candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
int nof_candidates =
srsran_pdcch_nr_locations_coreset(coreset, search_space, rnti, L, slot.idx, ncce_candidates);
int nof_candidates = srsran_pdcch_nr_locations_coreset(
coreset, search_space, pdsch_cfg.grant.rnti, L, slot.idx, ncce_candidates);
if (nof_candidates < SRSRAN_SUCCESS) {
ERROR("Error getting PDCCH candidates");
goto clean_exit;
@ -326,11 +354,8 @@ int main(int argc, char** argv)
dci_location.ncce = ncce_candidates[0];
dci_location.L = L;
// Setup DCI
srsran_dci_dl_nr_t dci_dl = {};
gettimeofday(&t[1], NULL);
if (work_gnb_dl(&enb_dl, &slot, search_space, &dci_dl, &dci_location, data_tx) < SRSRAN_ERROR) {
if (work_gnb_dl(&enb_dl, &slot, search_space, &dci_location, data_tx) < SRSRAN_ERROR) {
ERROR("Error running eNb DL");
goto clean_exit;
}
@ -339,8 +364,8 @@ int main(int argc, char** argv)
pdsch_encode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec);
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx;
srsran_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx);
pdsch_cfg.grant.tb[tb].softbuffer.rx = &softbuffer_rx;
srsran_softbuffer_rx_reset(pdsch_cfg.grant.tb[tb].softbuffer.rx);
}
gettimeofday(&t[1], NULL);
@ -358,23 +383,23 @@ int main(int argc, char** argv)
}
if (!pdsch_res[0].crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_grant.tb[0].tbs);
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs);
goto clean_exit;
}
if (memcmp(data_tx[0], data_rx[0], pdsch_grant.tb[0].tbs / 8) != 0) {
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_grant.tb[0].tbs);
if (memcmp(data_tx[0], data_rx[0], pdsch_cfg.grant.tb[0].tbs / 8) != 0) {
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs);
printf("Tx data: ");
srsran_vec_fprint_byte(stdout, data_tx[0], pdsch_grant.tb[0].tbs / 8);
srsran_vec_fprint_byte(stdout, data_tx[0], pdsch_cfg.grant.tb[0].tbs / 8);
printf("Rx data: ");
srsran_vec_fprint_byte(stdout, data_rx[0], pdsch_grant.tb[0].tbs / 8);
srsran_vec_fprint_byte(stdout, data_rx[0], pdsch_cfg.grant.tb[0].tbs / 8);
goto clean_exit;
}
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!", n_prb, mcs, pdsch_grant.tb[0].tbs, pdsch_res[0].evm);
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res[0].evm);
// Count the Tx/Rx'd number of bits
nof_bits += pdsch_grant.tb[0].tbs;
nof_bits += pdsch_cfg.grant.tb[0].tbs;
}
}
}

@ -125,8 +125,11 @@ int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, ui
srsran_sch_cfg_nr_t pdsch_cfg = {};
// Compute DL grant
if (srsran_ra_dl_dci_to_grant_nr(&enb_dl.carrier, &pdsch_hl_cfg, &grants[i].dci, &pdsch_cfg, &pdsch_cfg.grant)) {
if (srsran_ra_dl_dci_to_grant_nr(
&enb_dl.carrier, &dl_slot_cfg, &pdsch_hl_cfg, &grants[i].dci, &pdsch_cfg, &pdsch_cfg.grant) <
SRSRAN_SUCCESS) {
ERROR("Computing DL grant");
return false;
}
// Set soft buffer

@ -142,11 +142,11 @@ public:
* @param tti_rx The TTI in which the grant was received
* @param dci_dl The DL DCI message to store
*/
void set_dl_pending_grant(uint32_t tti_rx, const srsran_dci_dl_nr_t& dci_dl)
void set_dl_pending_grant(const srsran_slot_cfg_t& slot, const srsran_dci_dl_nr_t& dci_dl)
{
// Convert DL DCI to grant
srsran_sch_cfg_nr_t pdsch_cfg = {};
if (srsran_ra_dl_dci_to_grant_nr(&carrier, &cfg.pdsch, &dci_dl, &pdsch_cfg, &pdsch_cfg.grant)) {
if (srsran_ra_dl_dci_to_grant_nr(&carrier, &slot, &cfg.pdsch, &dci_dl, &pdsch_cfg, &pdsch_cfg.grant)) {
ERROR("Computing UL grant");
return;
}
@ -159,7 +159,7 @@ public:
}
// Calculate Receive TTI
tti_rx = TTI_ADD(tti_rx, pdsch_cfg.grant.k);
uint32_t tti_rx = TTI_ADD(slot.idx, pdsch_cfg.grant.k);
// Scope mutex to protect read/write the list
std::lock_guard<std::mutex> lock(pending_dl_grant_mutex);

@ -143,7 +143,7 @@ void cc_worker::decode_pdcch_dl()
}
// Enqueue UL grants
phy->set_dl_pending_grant(dl_slot_cfg.idx, dci_rx[i]);
phy->set_dl_pending_grant(dl_slot_cfg, dci_rx[i]);
}
if (logger.debug.enabled()) {

Loading…
Cancel
Save