srsLTE/lib/src/phy/phch/csi.c

413 lines
14 KiB
C

/**
* Copyright 2013-2022 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsran/phy/phch/csi.h"
#include "srsran/phy/utils/bit.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
#include <math.h>
#define CSI_WIDEBAND_CSI_NOF_BITS 4
#define CSI_DEFAULT_ALPHA 0.5f
/// Implements SNRI to CQI conversion
uint32_t csi_snri_db_to_cqi(srsran_csi_cqi_table_t table, float snri_db)
{
return 15;
}
// Implements CSI report triggers
static bool csi_report_trigger(const srsran_csi_hl_report_cfg_t* cfg, uint32_t slot_idx)
{
switch (cfg->type) {
case SRSRAN_CSI_REPORT_TYPE_PERIODIC:
return (slot_idx + cfg->periodic.period - cfg->periodic.offset) % cfg->periodic.period == 0;
default:; // Do nothing
}
return false;
}
static void csi_wideband_cri_ri_pmi_cqi_quantify(const srsran_csi_hl_report_cfg_t* cfg,
const srsran_csi_channel_measurements_t* channel_meas,
const srsran_csi_channel_measurements_t* interf_meas,
srsran_csi_report_value_t* report_value)
{
// Take SNR by default
float wideband_sinr_db = channel_meas->wideband_snr_db;
// If interference is provided, use the channel RSRP and interference EPRE to calculate the SINR
if (interf_meas != NULL) {
wideband_sinr_db = channel_meas->wideband_rsrp_dBm - interf_meas->wideband_epre_dBm;
}
// Fill quantified values
report_value->wideband_cri_ri_pmi_cqi.cqi = csi_snri_db_to_cqi(cfg->cqi_table, wideband_sinr_db);
report_value->wideband_cri_ri_pmi_cqi.ri = 0;
report_value->wideband_cri_ri_pmi_cqi.pmi = 0;
}
static uint32_t csi_wideband_cri_ri_pmi_cqi_nof_bits(const srsran_csi_report_cfg_t* cfg)
{
// Compute number of bits for CRI
uint32_t nof_bits_cri = 0;
if (cfg->K_csi_rs > 0) {
nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs));
}
switch (cfg->nof_ports) {
case 1:
return CSI_WIDEBAND_CSI_NOF_BITS + nof_bits_cri;
default:
ERROR("Invalid or not implemented number of ports (%d)", cfg->nof_ports);
}
return 0;
}
static uint32_t csi_wideband_cri_ri_pmi_cqi_pack(const srsran_csi_report_cfg_t* cfg,
const srsran_csi_report_value_t* value,
uint8_t* o_csi1)
{
// Compute number of bits for CRI
uint32_t nof_bits_cri = 0;
if (cfg->K_csi_rs > 0) {
nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs));
}
// Write wideband CQI
srsran_bit_unpack(value->wideband_cri_ri_pmi_cqi.cqi, &o_csi1, CSI_WIDEBAND_CSI_NOF_BITS);
// Compute number of bits for CRI and write
srsran_bit_unpack(value->cri, &o_csi1, nof_bits_cri);
return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS;
}
static uint32_t csi_wideband_cri_ri_pmi_cqi_unpack(const srsran_csi_report_cfg_t* cfg,
uint8_t* o_csi1,
srsran_csi_report_value_t* value)
{
// Compute number of bits for CRI
uint32_t nof_bits_cri = 0;
if (cfg->K_csi_rs > 0) {
nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs));
}
// Write wideband CQI
value->wideband_cri_ri_pmi_cqi.cqi = srsran_bit_pack(&o_csi1, CSI_WIDEBAND_CSI_NOF_BITS);
// Compute number of bits for CRI and write
value->cri = srsran_bit_pack(&o_csi1, nof_bits_cri);
return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS;
}
static uint32_t csi_none_nof_bits(const srsran_csi_report_cfg_t* cfg)
{
return cfg->K_csi_rs;
}
static uint32_t
csi_none_pack(const srsran_csi_report_cfg_t* cfg, const srsran_csi_report_value_t* value, uint8_t* o_csi1)
{
srsran_vec_u8_copy(o_csi1, (uint8_t*)value->none, cfg->K_csi_rs);
return cfg->K_csi_rs;
}
static uint32_t
csi_none_unpack(const srsran_csi_report_cfg_t* cfg, const uint8_t* o_csi1, srsran_csi_report_value_t* value)
{
srsran_vec_u8_copy((uint8_t*)value->none, o_csi1, cfg->K_csi_rs);
return cfg->K_csi_rs;
}
int srsran_csi_new_nzp_csi_rs_measurement(
const srsran_csi_hl_resource_cfg_t csi_resources[SRSRAN_CSI_MAX_NOF_RESOURCES],
srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES],
const srsran_csi_channel_measurements_t* new_measure,
uint32_t nzp_csi_rs_id)
{
if (csi_resources == NULL || measurements == NULL || new_measure == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Iterate all resources
for (uint32_t res_idx = 0; res_idx < SRSRAN_CSI_MAX_NOF_RESOURCES; res_idx++) {
// Skip resource is set to none
if (csi_resources[res_idx].type != SRSRAN_CSI_HL_RESOURCE_CFG_TYPE_NZP_CSI_RS_SSB) {
continue;
}
// Look for the NZP-CSI reource set
bool present = false;
for (uint32_t i = 0; i < SRSRAN_CSI_MAX_NOF_NZP_CSI_RS_RESOURCE_SETS_X_CONFIG && !present; i++) {
if (csi_resources[res_idx].nzp_csi_rs_ssb.nzp_csi_rs_resource_set_id_list[i] == nzp_csi_rs_id) {
present = true;
}
}
// Skip Resource if it does not contain the NZP-CSI-RS set
if (!present) {
continue;
}
// Filter measurements
measurements[res_idx].wideband_rsrp_dBm =
SRSRAN_VEC_SAFE_EMA(new_measure->wideband_rsrp_dBm, measurements[res_idx].wideband_rsrp_dBm, CSI_DEFAULT_ALPHA);
measurements[res_idx].wideband_epre_dBm =
SRSRAN_VEC_SAFE_EMA(new_measure->wideband_epre_dBm, measurements[res_idx].wideband_epre_dBm, CSI_DEFAULT_ALPHA);
measurements[res_idx].wideband_snr_db =
SRSRAN_VEC_SAFE_EMA(new_measure->wideband_snr_db, measurements[res_idx].wideband_snr_db, CSI_DEFAULT_ALPHA);
// Force rest
measurements[res_idx].cri = new_measure->cri;
measurements[res_idx].K_csi_rs = new_measure->K_csi_rs;
}
return SRSRAN_SUCCESS;
}
int srsran_csi_reports_generate(const srsran_csi_hl_cfg_t* cfg,
const srsran_slot_cfg_t* slot_cfg,
srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_SLOT_MAX_NOF_REPORT])
{
uint32_t count = 0;
// Check inputs
if (cfg == NULL || report_cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Make sure report configuration is initialised to zero
SRSRAN_MEM_ZERO(report_cfg, srsran_csi_report_cfg_t, SRSRAN_CSI_SLOT_MAX_NOF_REPORT);
// Iterate every possible configured CSI report
for (uint32_t i = 0; i < SRSRAN_CSI_MAX_NOF_REPORT; i++) {
// Skip if report is not configured or triggered
if (!csi_report_trigger(&cfg->reports[i], slot_cfg->idx)) {
continue;
}
if (count >= SRSRAN_CSI_SLOT_MAX_NOF_REPORT) {
ERROR("The number of CSI reports in the slot (%d) exceeds the maximum (%d)",
count++,
SRSRAN_CSI_SLOT_MAX_NOF_REPORT);
return SRSRAN_ERROR;
}
// Configure report
report_cfg[count].cfg = cfg->reports[i];
report_cfg[count].nof_ports = 1;
report_cfg[count].K_csi_rs = 1;
report_cfg[count].has_part2 = false;
count++;
}
return (int)count;
}
int srsran_csi_reports_quantify(const srsran_csi_report_cfg_t reports[SRSRAN_CSI_SLOT_MAX_NOF_REPORT],
const srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES],
srsran_csi_report_value_t report_value[SRSRAN_CSI_SLOT_MAX_NOF_REPORT])
{
uint32_t count = 0;
// Check inputs
if (reports == NULL || measurements == NULL || report_value == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Iterate every possible configured CSI report
for (uint32_t i = 0; i < SRSRAN_CSI_SLOT_MAX_NOF_REPORT; i++) {
// If the report is the last one, break
if (reports->cfg.type == SRSRAN_CSI_REPORT_TYPE_NONE) {
break;
}
// Select channel measurement
uint32_t channel_meas_id = reports[i].cfg.channel_meas_id;
if (channel_meas_id >= SRSRAN_CSI_MAX_NOF_RESOURCES) {
ERROR("Channel measurement ID (%d) is out of range", channel_meas_id);
return SRSRAN_ERROR;
}
const srsran_csi_channel_measurements_t* channel_meas = &measurements[channel_meas_id];
// Select interference measurement
const srsran_csi_channel_measurements_t* interf_meas = NULL;
if (reports[i].cfg.interf_meas_present) {
uint32_t interf_meas_id = reports[i].cfg.interf_meas_id;
if (interf_meas_id >= SRSRAN_CSI_MAX_NOF_RESOURCES) {
ERROR("Interference measurement ID (%d) is out of range", interf_meas_id);
return SRSRAN_ERROR;
}
interf_meas = &measurements[interf_meas_id];
}
// Quantify measurements according to frequency and quantity configuration
if (reports[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
reports[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
csi_wideband_cri_ri_pmi_cqi_quantify(&reports[i].cfg, channel_meas, interf_meas, &report_value[count]);
count++;
} else {
; // Ignore other types
}
}
return (int)count;
}
int srsran_csi_part1_nof_bits(const srsran_csi_report_cfg_t* report_list, uint32_t nof_reports)
{
uint32_t count = 0;
// Check input pointer
if (report_list == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Iterate all report configurations
for (uint32_t i = 0; i < nof_reports; i++) {
const srsran_csi_report_cfg_t* report = &report_list[i];
if (report->cfg.quantity && report->cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report);
} else if (report->cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_nof_bits(report);
}
}
return (int)count;
}
int srsran_csi_part2_nof_bits(const srsran_csi_report_cfg_t* report_list, uint32_t nof_reports)
{
uint32_t count = 0;
// Check input pointer
if (report_list == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
return (int)count;
}
bool srsran_csi_has_part2(const srsran_csi_report_cfg_t* report_list, uint32_t nof_reports)
{
if (report_list == NULL || nof_reports == 0) {
return false;
}
for (uint32_t i = 0; i < nof_reports; i++) {
if (report_list[i].has_part2) {
return true;
}
}
return false;
}
int srsran_csi_part1_pack(const srsran_csi_report_cfg_t* report_cfg,
const srsran_csi_report_value_t* report_value,
uint32_t nof_reports,
uint8_t* o_csi1,
uint32_t max_o_csi1)
{
uint32_t count = 0;
if (report_cfg == NULL || report_value == NULL || o_csi1 == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
int n = srsran_csi_part1_nof_bits(report_cfg, nof_reports);
if (n > (int)max_o_csi1) {
ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n);
return SRSRAN_ERROR;
}
for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) {
if (report_cfg[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]);
} else if (report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_pack(&report_cfg[i], &report_value[i], &o_csi1[count]);
} else {
ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented",
report_cfg[i].cfg.freq_cfg,
report_cfg[i].cfg.quantity);
}
}
return (int)count;
}
int srsran_csi_part1_unpack(const srsran_csi_report_cfg_t* report_cfg,
uint32_t nof_reports,
uint8_t* o_csi1,
uint32_t max_o_csi1,
srsran_csi_report_value_t* report_value)
{
uint32_t count = 0;
if (report_cfg == NULL || report_value == NULL || o_csi1 == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
int n = srsran_csi_part1_nof_bits(report_cfg, nof_reports);
if (n > (int)max_o_csi1) {
ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n);
return SRSRAN_ERROR;
}
for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) {
if (report_cfg[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]);
} else if (report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]);
} else {
ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented",
report_cfg[i].cfg.freq_cfg,
report_cfg[i].cfg.quantity);
}
}
return (int)count;
}
uint32_t srsran_csi_str(const srsran_csi_report_cfg_t* report_cfg,
const srsran_csi_report_value_t* report_value,
uint32_t nof_reports,
char* str,
uint32_t str_len)
{
uint32_t len = 0;
for (uint32_t i = 0; i < nof_reports; i++) {
if (report_cfg[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
len = srsran_print_check(str, str_len, len, "cqi=%d ", report_value[i].wideband_cri_ri_pmi_cqi.cqi);
} else if (report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
char tmp[20] = {};
srsran_vec_sprint_bin(tmp, sizeof(tmp), report_value[i].none, report_cfg->K_csi_rs);
len = srsran_print_check(str, str_len, len, "csi=%s ", tmp);
}
}
return len;
}