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

1234 lines
39 KiB
C
Raw Normal View History

/**
2022-04-29 00:28:44 -07:00
* Copyright 2013-2022 Software Radio Systems Limited
*
2021-04-22 01:59:40 -07:00
* This file is part of srsRAN.
*
2021-04-22 01:59:40 -07:00
* srsRAN is free software: you can redistribute it and/or modify
2021-03-28 14:12:42 -07:00
* 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.
*
2021-04-22 01:59:40 -07:00
* srsRAN is distributed in the hope that it will be useful,
2021-03-28 14:12:42 -07:00
* 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.
*
2021-03-28 14:12:42 -07:00
* 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/.
*
*/
2021-03-19 03:45:56 -07:00
#include "srsran/srsran.h"
2019-04-23 01:53:11 -07:00
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
2019-04-23 01:53:11 -07:00
#include <string.h>
2017-09-05 06:26:36 -07:00
2018-06-06 07:59:00 -07:00
#include <pthread.h>
#include <semaphore.h>
2017-09-01 10:32:57 -07:00
#include "prb_dl.h"
2021-03-19 03:45:56 -07:00
#include "srsran/phy/phch/pdsch.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
2018-09-17 03:32:37 -07:00
#ifdef LV_HAVE_SSE
#include <immintrin.h>
#endif /* LV_HAVE_SSE */
2021-03-19 03:45:56 -07:00
#define MAX_PDSCH_RE(cp) (2 * SRSRAN_CP_NSYMB(cp) * 12)
2019-04-23 01:53:11 -07:00
/* 3GPP 36.213 Table 5.2-1: The cell-specific ratio rho_B / rho_A for 1, 2, or 4 cell specific antenna ports */
const static float pdsch_cfg_cell_specific_ratio_table[2][4] = {
/* One antenna port */ {1.0f / 1.0f, 4.0f / 5.0f, 3.0f / 5.0f, 2.0f / 5.0f},
/* Two or more antenna port */ {5.0f / 4.0f, 1.0f / 1.0f, 3.0f / 4.0f, 1.0f / 2.0f}};
2021-03-19 03:45:56 -07:00
const static srsran_mod_t modulations[5] = {SRSRAN_MOD_BPSK,
SRSRAN_MOD_QPSK,
SRSRAN_MOD_16QAM,
SRSRAN_MOD_64QAM,
SRSRAN_MOD_256QAM};
2018-06-06 07:59:00 -07:00
typedef struct {
/* Thread identifier: they must set before thread creation */
pthread_t pthread;
uint32_t tb_idx;
void* pdsch_ptr;
bool* ack;
2018-06-06 07:59:00 -07:00
/* Configuration Encoder/Decoder: they must be set before posting start semaphore */
2021-03-19 03:45:56 -07:00
srsran_dl_sf_cfg_t* sf;
srsran_pdsch_cfg_t* cfg;
srsran_sch_t dl_sch;
2018-06-06 07:59:00 -07:00
/* Encoder/Decoder data pointers: they must be set before posting start semaphore */
2021-03-19 03:45:56 -07:00
srsran_pdsch_res_t* data;
2018-06-06 07:59:00 -07:00
/* Execution status */
int ret_status;
/* Semaphores */
sem_t start;
sem_t finish;
2018-06-11 04:12:46 -07:00
/* Thread flags */
bool started;
2018-06-06 07:59:00 -07:00
bool quit;
2021-03-19 03:45:56 -07:00
} srsran_pdsch_coworker_t;
2018-06-06 07:59:00 -07:00
2021-03-19 03:45:56 -07:00
static void* srsran_pdsch_decode_thread(void* arg);
2018-06-06 07:59:00 -07:00
2021-03-19 03:45:56 -07:00
static inline bool pdsch_cp_skip_symbol(const srsran_cell_t* cell,
const srsran_pdsch_grant_t* grant,
2020-04-14 09:10:43 -07:00
uint32_t sf_idx,
uint32_t s,
uint32_t l,
uint32_t n)
{
2020-04-14 09:10:43 -07:00
// Skip center block signals
if ((n >= cell->nof_prb / 2 - 3 && n < cell->nof_prb / 2 + 3 + (cell->nof_prb % 2))) {
2021-03-19 03:45:56 -07:00
if (cell->frame_type == SRSRAN_FDD) {
2020-04-14 09:10:43 -07:00
// FDD PSS/SSS
if (s == 0 && (sf_idx == 0 || sf_idx == 5) && (l >= grant->nof_symb_slot[s] - 2)) {
return true;
}
} else {
// TDD SSS
if (s == 1 && (sf_idx == 0 || sf_idx == 5) && (l >= grant->nof_symb_slot[s] - 1)) {
return true;
}
// TDD PSS
if (s == 0 && (sf_idx == 1 || sf_idx == 6) && (l == 2)) {
return true;
}
}
// PBCH same in FDD and TDD
if (s == 1 && sf_idx == 0 && l < 4) {
return true;
}
}
2020-04-14 09:10:43 -07:00
return false;
}
2021-03-19 03:45:56 -07:00
static inline uint32_t pdsch_cp_crs_offset(const srsran_cell_t* cell, uint32_t l, bool has_crs)
2020-04-14 09:10:43 -07:00
{
// No CRS, return 0
if (!has_crs) {
return 0;
2014-06-17 07:32:19 -07:00
}
2020-04-14 09:10:43 -07:00
// For 1 port cell
if (cell->nof_ports == 1) {
if (l == 0) {
return cell->id % 6;
2019-04-23 01:53:11 -07:00
} else {
2020-04-14 09:10:43 -07:00
return (cell->id + 3) % 6;
2019-04-23 01:53:11 -07:00
}
2020-04-14 09:10:43 -07:00
}
// For more 2 ports or more
return cell->id % 3;
}
2021-03-19 03:45:56 -07:00
static int srsran_pdsch_cp(const srsran_pdsch_t* q,
2020-04-14 09:10:43 -07:00
cf_t* input,
cf_t* output,
2021-03-19 03:45:56 -07:00
const srsran_pdsch_grant_t* grant,
2020-04-14 09:10:43 -07:00
uint32_t lstart_grant,
uint32_t sf_idx,
bool put)
{
cf_t* in_ptr = input;
cf_t* out_ptr = output;
uint32_t nof_refs = (q->cell.nof_ports == 1) ? 2 : 4;
// Iterate over slots
2021-03-19 03:45:56 -07:00
for (uint32_t s = 0; s < SRSRAN_NOF_SLOTS_PER_SF; s++) {
2020-04-14 09:10:43 -07:00
// Skip PDCCH symbols
uint32_t lstart = (s == 0) ? lstart_grant : 0;
// Iterate over symbols
for (uint32_t l = lstart; l < grant->nof_symb_slot[s]; l++) {
2021-03-19 03:45:56 -07:00
bool has_crs = SRSRAN_SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports);
2020-04-14 09:10:43 -07:00
uint32_t crs_offset = pdsch_cp_crs_offset(&q->cell, l, has_crs);
// Grid symbol
uint32_t lp = l + s * grant->nof_symb_slot[0];
// Iterate over PRB
for (uint32_t n = 0; n < q->cell.nof_prb; n++) {
// If this PRB is assigned
if (grant->prb_idx[s][n]) {
2020-04-14 09:10:43 -07:00
bool skip = pdsch_cp_skip_symbol(&q->cell, grant, sf_idx, s, l, n);
2019-04-23 01:53:11 -07:00
2020-04-14 09:10:43 -07:00
// Get grid pointer
if (put) {
2021-03-19 03:45:56 -07:00
out_ptr = &output[(lp * q->cell.nof_prb + n) * SRSRAN_NRE];
2014-06-17 07:32:19 -07:00
} else {
2021-03-19 03:45:56 -07:00
in_ptr = &input[(lp * q->cell.nof_prb + n) * SRSRAN_NRE];
2014-06-17 07:32:19 -07:00
}
2020-04-14 09:10:43 -07:00
// This is a symbol in a normal PRB with or without references
2020-04-14 09:10:43 -07:00
if (!skip) {
if (has_crs) {
prb_cp_ref(&in_ptr, &out_ptr, crs_offset, nof_refs, nof_refs, put);
} else {
prb_cp(&in_ptr, &out_ptr, 1);
}
2020-04-14 09:10:43 -07:00
} else if (q->cell.nof_prb % 2 != 0) {
// This is a symbol in a PRB with PBCH or Synch signals (SS).
// If the number or total PRB is odd, half of the the PBCH or SS will fall into the symbol
if (n == q->cell.nof_prb / 2 - 3) {
2020-04-14 09:10:43 -07:00
// Lower sync block half RB
if (has_crs) {
prb_cp_ref(&in_ptr, &out_ptr, crs_offset, nof_refs, nof_refs / 2, put);
} else {
prb_cp_half(&in_ptr, &out_ptr, 1);
}
} else if (n == q->cell.nof_prb / 2 + 3) {
2020-04-14 09:10:43 -07:00
// Upper sync block half RB
// Skip half RB on the grid
if (put) {
2021-03-19 03:45:56 -07:00
out_ptr += SRSRAN_NRE / 2;
} else {
2021-03-19 03:45:56 -07:00
in_ptr += SRSRAN_NRE / 2;
}
2020-04-14 09:10:43 -07:00
if (has_crs) {
prb_cp_ref(&in_ptr, &out_ptr, crs_offset, nof_refs, nof_refs / 2, put);
} else {
prb_cp_half(&in_ptr, &out_ptr, 1);
}
}
2014-06-17 07:32:19 -07:00
}
}
2019-04-23 01:53:11 -07:00
}
2014-06-17 07:32:19 -07:00
}
}
2019-04-23 01:53:11 -07:00
int r;
2014-06-17 07:32:19 -07:00
if (put) {
r = abs((int)(input - in_ptr));
2014-06-17 07:32:19 -07:00
} else {
r = abs((int)(output - out_ptr));
2014-06-17 07:32:19 -07:00
}
2019-04-23 01:53:11 -07:00
return r;
}
/**
* Puts PDSCH in slot number 1
*
* Returns the number of symbols written to sf_symbols
*
* 36.211 10.3 section 6.3.5
*/
2021-03-19 03:45:56 -07:00
int srsran_pdsch_put(srsran_pdsch_t* q,
cf_t* symbols,
cf_t* sf_symbols,
2021-03-19 03:45:56 -07:00
srsran_pdsch_grant_t* grant,
uint32_t lstart,
uint32_t subframe)
{
2021-03-19 03:45:56 -07:00
return srsran_pdsch_cp(q, symbols, sf_symbols, grant, lstart, subframe, true);
}
/**
* Extracts PDSCH from slot number 1
*
* Returns the number of symbols written to PDSCH
*
* 36.211 10.3 section 6.3.5
*/
2021-03-19 03:45:56 -07:00
int srsran_pdsch_get(srsran_pdsch_t* q,
cf_t* sf_symbols,
cf_t* symbols,
2021-03-19 03:45:56 -07:00
srsran_pdsch_grant_t* grant,
uint32_t lstart,
uint32_t subframe)
{
2021-03-19 03:45:56 -07:00
return srsran_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false);
}
2017-09-05 06:26:36 -07:00
/** Initializes the PDSCH transmitter and receiver */
2021-03-19 03:45:56 -07:00
static int pdsch_init(srsran_pdsch_t* q, uint32_t max_prb, bool is_ue, uint32_t nof_antennas)
{
2021-03-19 03:45:56 -07:00
int ret = SRSRAN_ERROR_INVALID_INPUTS;
2014-06-17 07:32:19 -07:00
if (q != NULL) {
2021-03-19 03:45:56 -07:00
bzero(q, sizeof(srsran_pdsch_t));
ret = SRSRAN_ERROR;
2017-09-05 06:26:36 -07:00
q->max_re = max_prb * MAX_PDSCH_RE(q->cell.cp);
q->is_ue = is_ue;
q->nof_rx_antennas = nof_antennas;
INFO("Init PDSCH: %d PRBs, max_symbols: %d", max_prb, q->max_re);
2014-06-17 07:32:19 -07:00
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MOD_NITEMS; i++) {
if (srsran_modem_table_lte(&q->mod[i], modulations[i])) {
goto clean;
}
2021-03-19 03:45:56 -07:00
srsran_modem_table_bytes(&q->mod[i]);
}
2017-09-05 06:26:36 -07:00
2021-03-19 03:45:56 -07:00
if (srsran_sch_init(&q->dl_sch)) {
2017-09-05 06:26:36 -07:00
ERROR("Initiating DL SCH");
2014-06-17 07:32:19 -07:00
goto clean;
}
2017-09-05 06:26:36 -07:00
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
2017-09-05 06:26:36 -07:00
// Allocate int16_t for reception (LLRs)
2021-03-19 03:45:56 -07:00
q->e[i] = srsran_vec_i16_malloc(q->max_re * srsran_mod_bits_x_symbol(SRSRAN_MOD_256QAM));
2017-09-05 06:26:36 -07:00
if (!q->e[i]) {
goto clean;
}
2021-03-19 03:45:56 -07:00
q->d[i] = srsran_vec_cf_malloc(q->max_re);
2017-09-05 06:26:36 -07:00
if (!q->d[i]) {
goto clean;
}
// If it is the UE, allocate EVM buffer, for only minimum PRB
if (is_ue) {
2021-03-19 03:45:56 -07:00
q->evm_buffer[i] = srsran_evm_buffer_alloc(srsran_ra_tbs_from_idx(SRSRAN_RA_NOF_TBS_IDX - 1, 6));
if (!q->evm_buffer[i]) {
ERROR("Allocating EVM buffer");
goto clean;
}
}
2014-06-17 07:32:19 -07:00
}
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MAX_PORTS; i++) {
q->x[i] = srsran_vec_cf_malloc(q->max_re);
2015-03-18 11:14:24 -07:00
if (!q->x[i]) {
goto clean;
}
2021-03-19 03:45:56 -07:00
q->symbols[i] = srsran_vec_cf_malloc(q->max_re);
2017-09-05 06:26:36 -07:00
if (!q->symbols[i]) {
goto clean;
}
if (q->is_ue) {
2021-03-19 03:45:56 -07:00
for (int j = 0; j < SRSRAN_MAX_PORTS; j++) {
q->ce[i][j] = srsran_vec_cf_malloc(q->max_re);
if (!q->ce[i][j]) {
goto clean;
}
}
}
}
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
2019-04-23 01:53:11 -07:00
if (!q->csi[i]) {
2021-03-19 03:45:56 -07:00
q->csi[i] = srsran_vec_f_malloc(q->max_re * 2);
2019-04-23 01:53:11 -07:00
if (!q->csi[i]) {
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR;
2019-04-23 01:53:11 -07:00
}
}
}
2021-03-19 03:45:56 -07:00
ret = SRSRAN_SUCCESS;
}
2017-09-05 06:26:36 -07:00
2019-04-23 01:53:11 -07:00
clean:
2021-03-19 03:45:56 -07:00
if (ret == SRSRAN_ERROR) {
srsran_pdsch_free(q);
2014-06-17 07:32:19 -07:00
}
return ret;
}
2021-03-19 03:45:56 -07:00
int srsran_pdsch_init_ue(srsran_pdsch_t* q, uint32_t max_prb, uint32_t nof_antennas)
{
2017-09-05 06:26:36 -07:00
return pdsch_init(q, max_prb, true, nof_antennas);
}
2021-03-19 03:45:56 -07:00
int srsran_pdsch_init_enb(srsran_pdsch_t* q, uint32_t max_prb)
{
2017-09-05 06:26:36 -07:00
return pdsch_init(q, max_prb, false, 0);
}
2021-03-19 03:45:56 -07:00
static void srsran_pdsch_disable_coworker(srsran_pdsch_t* q)
{
2021-03-19 03:45:56 -07:00
srsran_pdsch_coworker_t* h = (srsran_pdsch_coworker_t*)q->coworker_ptr;
2018-06-06 07:59:00 -07:00
if (h) {
/* Stop threads */
h->quit = true;
sem_post(&h->start);
pthread_join(h->pthread, NULL);
pthread_detach(h->pthread);
2021-03-19 03:45:56 -07:00
srsran_sch_free(&h->dl_sch);
2018-06-06 07:59:00 -07:00
free(h);
q->coworker_ptr = NULL;
}
}
2021-03-19 03:45:56 -07:00
int srsran_pdsch_enable_coworker(srsran_pdsch_t* q)
2019-04-23 01:53:11 -07:00
{
2021-03-19 03:45:56 -07:00
int ret = SRSRAN_SUCCESS;
2019-04-23 01:53:11 -07:00
if (!q->coworker_ptr) {
2021-03-19 03:45:56 -07:00
srsran_pdsch_coworker_t* h = calloc(sizeof(srsran_pdsch_coworker_t), 1);
2019-04-23 01:53:11 -07:00
if (!h) {
ERROR("Allocating coworker");
2021-03-19 03:45:56 -07:00
ret = SRSRAN_ERROR;
2019-04-23 01:53:11 -07:00
goto clean;
}
q->coworker_ptr = h;
2021-03-19 03:45:56 -07:00
if (srsran_sch_init(&h->dl_sch)) {
2019-04-23 01:53:11 -07:00
ERROR("Initiating DL SCH");
2021-03-19 03:45:56 -07:00
ret = SRSRAN_ERROR;
2019-04-23 01:53:11 -07:00
goto clean;
}
if (sem_init(&h->start, 0, 0)) {
ERROR("Creating semaphore");
2021-03-19 03:45:56 -07:00
ret = SRSRAN_ERROR;
2019-04-23 01:53:11 -07:00
goto clean;
}
if (sem_init(&h->finish, 0, 0)) {
ERROR("Creating semaphore");
2021-03-19 03:45:56 -07:00
ret = SRSRAN_ERROR;
2019-04-23 01:53:11 -07:00
goto clean;
}
2021-03-19 03:45:56 -07:00
pthread_create(&h->pthread, NULL, srsran_pdsch_decode_thread, (void*)h);
2019-04-23 01:53:11 -07:00
}
clean:
if (ret) {
2021-03-19 03:45:56 -07:00
srsran_pdsch_disable_coworker(q);
2019-04-23 01:53:11 -07:00
}
return ret;
}
2021-03-19 03:45:56 -07:00
void srsran_pdsch_free(srsran_pdsch_t* q)
{
2021-03-19 03:45:56 -07:00
srsran_pdsch_disable_coworker(q);
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
2017-09-05 06:26:36 -07:00
if (q->e[i]) {
free(q->e[i]);
}
2014-06-17 07:32:19 -07:00
2017-09-05 06:26:36 -07:00
if (q->d[i]) {
free(q->d[i]);
}
if (q->csi[i]) {
free(q->csi[i]);
}
if (q->evm_buffer[i]) {
2021-03-19 03:45:56 -07:00
srsran_evm_free(q->evm_buffer[i]);
}
2014-06-17 07:32:19 -07:00
}
2017-09-05 06:26:36 -07:00
/* Free sch objects */
2021-03-19 03:45:56 -07:00
srsran_sch_free(&q->dl_sch);
2017-09-05 06:26:36 -07:00
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MAX_PORTS; i++) {
2015-03-18 11:14:24 -07:00
if (q->x[i]) {
free(q->x[i]);
2014-06-17 07:32:19 -07:00
}
2017-09-05 06:26:36 -07:00
if (q->symbols[i]) {
free(q->symbols[i]);
}
if (q->is_ue) {
2021-03-19 03:45:56 -07:00
for (int j = 0; j < SRSRAN_MAX_PORTS; j++) {
2017-09-05 06:26:36 -07:00
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
2014-06-17 07:32:19 -07:00
}
}
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MOD_NITEMS; i++) {
srsran_modem_table_free(&q->mod[i]);
2014-06-17 07:32:19 -07:00
}
2021-03-19 03:45:56 -07:00
bzero(q, sizeof(srsran_pdsch_t));
}
2021-03-19 03:45:56 -07:00
int srsran_pdsch_set_cell(srsran_pdsch_t* q, srsran_cell_t cell)
{
2021-03-19 03:45:56 -07:00
int ret = SRSRAN_ERROR_INVALID_INPUTS;
2021-03-19 03:45:56 -07:00
if (q != NULL && srsran_cell_isvalid(&cell)) {
2019-04-23 01:53:11 -07:00
q->cell = cell;
q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp);
// Resize EVM buffer, only for UE
if (q->is_ue) {
2021-03-19 03:45:56 -07:00
for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
srsran_evm_buffer_resize(q->evm_buffer[i], srsran_ra_tbs_from_idx(SRSRAN_RA_NOF_TBS_IDX - 1, cell.nof_prb));
}
}
INFO("PDSCH: Cell config PCI=%d, %d ports, %d PRBs, max_symbols: %d",
q->cell.id,
q->cell.nof_ports,
q->cell.nof_prb,
q->max_re);
2021-03-19 03:45:56 -07:00
ret = SRSRAN_SUCCESS;
}
return ret;
}
2021-03-19 03:45:56 -07:00
static float apply_power_allocation(srsran_pdsch_t* q, srsran_pdsch_cfg_t* cfg, cf_t* sf_symbols_m[SRSRAN_MAX_PORTS])
{
2019-04-23 01:53:11 -07:00
uint32_t nof_symbols_slot = cfg->grant.nof_symb_slot[0];
2021-03-19 03:45:56 -07:00
uint32_t nof_re_symbol = SRSRAN_NRE * q->cell.nof_prb;
2019-04-23 01:53:11 -07:00
/* Set power allocation according to 3GPP 36.213 clause 5.2 Downlink power allocation */
2021-03-19 03:45:56 -07:00
float rho_a = srsran_convert_dB_to_amplitude(cfg->p_a) * ((q->cell.nof_ports == 1) ? 1.0f : M_SQRT2);
2019-04-23 01:53:11 -07:00
uint32_t idx0 = (q->cell.nof_ports == 1) ? 0 : 1;
float cell_specific_ratio = pdsch_cfg_cell_specific_ratio_table[idx0][cfg->p_b];
float rho_b = sqrtf(cell_specific_ratio);
/* Apply rho_b if required according to 3GPP 36.213 Table 5.2-2 */
if (rho_b != 0.0f && rho_b != 1.0f) {
float scaling = 1.0f / rho_b;
for (uint32_t i = 0; i < q->nof_rx_antennas; i++) {
for (uint32_t j = 0; j < 2; j++) {
cf_t* ptr;
ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 0);
2021-03-19 03:45:56 -07:00
srsran_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
if (q->cell.cp == SRSRAN_CP_NORM) {
2019-04-23 01:53:11 -07:00
ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 4);
2021-03-19 03:45:56 -07:00
srsran_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
} else {
2019-04-23 01:53:11 -07:00
ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 3);
2021-03-19 03:45:56 -07:00
srsran_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
2017-09-05 06:26:36 -07:00
}
2019-04-23 01:53:11 -07:00
if (q->cell.nof_ports == 4) {
ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 1);
2021-03-19 03:45:56 -07:00
srsran_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
2017-09-05 06:26:36 -07:00
}
2019-04-23 01:53:11 -07:00
}
2017-09-05 06:26:36 -07:00
}
}
2019-04-23 01:53:11 -07:00
return rho_a;
2017-09-05 06:26:36 -07:00
}
2021-03-19 03:45:56 -07:00
static void csi_correction(srsran_pdsch_t* q, srsran_pdsch_cfg_t* cfg, uint32_t codeword_idx, uint32_t tb_idx, void* e)
{
uint32_t qm = srsran_mod_bits_x_symbol(cfg->grant.tb[tb_idx].mod);
if (qm == 0) {
return;
}
2021-03-19 03:45:56 -07:00
const uint32_t csi_max_idx = srsran_vec_max_fi(q->csi[codeword_idx], cfg->grant.tb[tb_idx].nof_bits / qm);
float csi_max = 1.0f;
2019-04-23 01:53:11 -07:00
if (csi_max_idx < cfg->grant.tb[tb_idx].nof_bits / qm) {
csi_max = q->csi[codeword_idx][csi_max_idx];
}
int8_t* e_b = e;
int16_t* e_s = e;
float* csi_v = q->csi[codeword_idx];
2018-09-17 03:32:37 -07:00
if (q->llr_is_8bit) {
2019-04-23 01:53:11 -07:00
for (int i = 0; i < cfg->grant.tb[tb_idx].nof_bits / qm; i++) {
2018-09-17 03:32:37 -07:00
const float csi = *(csi_v++) / csi_max;
for (int k = 0; k < qm; k++) {
*e_b = (int8_t)((float)*e_b * csi);
2018-09-17 03:32:37 -07:00
e_b++;
}
2018-09-17 03:32:37 -07:00
}
} else {
int i = 0;
2019-07-12 05:11:26 -07:00
#ifdef LV_HAVE_SSE
2018-09-17 03:32:37 -07:00
__m128 _csi_scale = _mm_set1_ps(INT16_MAX / csi_max);
2019-04-23 01:53:11 -07:00
__m64* _e = (__m64*)e;
2018-09-17 03:32:37 -07:00
2019-04-23 01:53:11 -07:00
switch (cfg->grant.tb[tb_idx].mod) {
2021-03-19 03:45:56 -07:00
case SRSRAN_MOD_QPSK:
2019-04-23 01:53:11 -07:00
for (; i < cfg->grant.tb[tb_idx].nof_bits - 3; i += 4) {
2018-09-17 03:32:37 -07:00
__m128 _csi1 = _mm_set1_ps(*(csi_v++));
__m128 _csi2 = _mm_set1_ps(*(csi_v++));
_csi1 = _mm_blend_ps(_csi1, _csi2, 3);
2018-09-17 03:32:37 -07:00
_csi1 = _mm_mul_ps(_csi1, _csi_scale);
_e[0] = _mm_mulhi_pi16(_e[0], _mm_cvtps_pi16(_csi1));
_e += 1;
}
break;
2021-03-19 03:45:56 -07:00
case SRSRAN_MOD_16QAM:
2019-04-23 01:53:11 -07:00
for (; i < cfg->grant.tb[tb_idx].nof_bits - 3; i += 4) {
2018-09-17 03:32:37 -07:00
__m128 _csi = _mm_set1_ps(*(csi_v++));
_csi = _mm_mul_ps(_csi, _csi_scale);
_e[0] = _mm_mulhi_pi16(_e[0], _mm_cvtps_pi16(_csi));
_e += 1;
}
break;
2021-03-19 03:45:56 -07:00
case SRSRAN_MOD_64QAM:
2019-04-23 01:53:11 -07:00
for (; i < cfg->grant.tb[tb_idx].nof_bits - 11; i += 12) {
2018-09-17 03:32:37 -07:00
__m128 _csi1 = _mm_set1_ps(*(csi_v++));
__m128 _csi3 = _mm_set1_ps(*(csi_v++));
_csi1 = _mm_mul_ps(_csi1, _csi_scale);
_csi3 = _mm_mul_ps(_csi3, _csi_scale);
2018-09-17 03:32:37 -07:00
__m128 _csi2 = _mm_blend_ps(_csi1, _csi3, 3);
_e[0] = _mm_mulhi_pi16(_e[0], _mm_cvtps_pi16(_csi1));
_e[1] = _mm_mulhi_pi16(_e[1], _mm_cvtps_pi16(_csi2));
_e[2] = _mm_mulhi_pi16(_e[2], _mm_cvtps_pi16(_csi3));
_e += 3;
}
break;
2021-03-19 03:45:56 -07:00
case SRSRAN_MOD_BPSK:
2018-09-17 03:32:37 -07:00
break;
2021-03-19 03:45:56 -07:00
case SRSRAN_MOD_256QAM:
for (; i < cfg->grant.tb[tb_idx].nof_bits - 7; i += 8) {
__m128 _csi = _mm_set1_ps(*(csi_v++));
_csi = _mm_mul_ps(_csi, _csi_scale);
_e[0] = _mm_mulhi_pi16(_e[0], _mm_cvtps_pi16(_csi));
2019-07-12 05:11:26 -07:00
_e[1] = _mm_mulhi_pi16(_e[1], _mm_cvtps_pi16(_csi));
_e += 2;
}
break;
2021-03-19 03:45:56 -07:00
case SRSRAN_MOD_NITEMS:
2020-02-27 08:00:54 -08:00
default:; // Do nothing
2018-09-17 03:32:37 -07:00
}
i /= qm;
#endif /* LV_HAVE_SSE */
2019-04-23 01:53:11 -07:00
for (; i < cfg->grant.tb[tb_idx].nof_bits / qm; i++) {
2018-09-17 03:32:37 -07:00
const float csi = q->csi[codeword_idx][i] / csi_max;
for (int k = 0; k < qm; k++) {
e_s[qm * i + k] = (int16_t)((float)e_s[qm * i + k] * csi);
}
}
}
}
2021-03-19 03:45:56 -07:00
static void pdsch_decode_debug(srsran_pdsch_t* q,
srsran_pdsch_cfg_t* cfg,
cf_t* sf_symbols[SRSRAN_MAX_PORTS],
cf_t* ce[SRSRAN_MAX_PORTS][SRSRAN_MAX_PORTS])
2019-04-23 01:53:11 -07:00
{
2021-03-19 03:45:56 -07:00
if (SRSRAN_VERBOSE_ISDEBUG()) {
2019-04-23 01:53:11 -07:00
char filename[FILENAME_MAX];
for (int j = 0; j < q->nof_rx_antennas; j++) {
if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: received subframe symbols", filename);
2021-03-19 03:45:56 -07:00
srsran_vec_save_file(filename, sf_symbols[j], SRSRAN_NOF_RE(q->cell) * sizeof(cf_t));
2019-04-23 01:53:11 -07:00
for (int i = 0; i < q->cell.nof_ports; i++) {
if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d", filename, j, i);
2021-03-19 03:45:56 -07:00
srsran_vec_save_file(filename, ce[i][j], SRSRAN_NOF_RE(q->cell) * sizeof(cf_t));
2019-04-23 01:53:11 -07:00
}
}
for (int i = 0; i < cfg->grant.nof_layers; i++) {
if (snprintf(filename, FILENAME_MAX, "pdsch_symbols_%d.dat", i) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: symbols after equalization", filename);
2021-03-19 03:45:56 -07:00
srsran_vec_save_file(filename, q->d[i], cfg->grant.nof_re * sizeof(cf_t));
2019-04-23 01:53:11 -07:00
if (snprintf(filename, FILENAME_MAX, "llr_%d.dat", i) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: LLR estimates after demodulation and descrambling", filename);
2021-03-19 03:45:56 -07:00
srsran_vec_save_file(filename, q->e[i], cfg->grant.tb[0].nof_bits * sizeof(int16_t));
2019-04-23 01:53:11 -07:00
}
}
}
2021-03-19 03:45:56 -07:00
static int srsran_pdsch_codeword_decode(srsran_pdsch_t* q,
srsran_dl_sf_cfg_t* sf,
srsran_pdsch_cfg_t* cfg,
srsran_sch_t* dl_sch,
srsran_pdsch_res_t* data,
2019-04-23 01:53:11 -07:00
uint32_t tb_idx,
bool* ack)
{
2021-03-19 03:45:56 -07:00
srsran_ra_tb_t* mcs = &cfg->grant.tb[tb_idx];
2019-04-23 01:53:11 -07:00
uint32_t rv = mcs->rv;
uint32_t codeword_idx = mcs->cw_idx;
uint32_t nof_layers = cfg->grant.nof_layers;
2021-03-19 03:45:56 -07:00
srsran_softbuffer_rx_t* softbuffer = cfg->softbuffers.rx[tb_idx];
2019-04-23 01:53:11 -07:00
2021-03-19 03:45:56 -07:00
int ret = SRSRAN_ERROR_INVALID_INPUTS;
2017-09-05 06:26:36 -07:00
2019-04-23 01:53:11 -07:00
if (softbuffer && data && ack && cfg->grant.tb[tb_idx].nof_bits && cfg->grant.nof_re) {
INFO("Decoding PDSCH SF: %d (CW%d -> TB%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d",
2019-04-23 01:53:11 -07:00
sf->tti % 10,
codeword_idx,
tb_idx,
2021-03-19 03:45:56 -07:00
srsran_mod_string(mcs->mod),
2019-04-23 01:53:11 -07:00
mcs->tbs,
cfg->grant.nof_re,
cfg->grant.tb[tb_idx].nof_bits,
rv);
2017-09-05 06:26:36 -07:00
/* demodulate symbols
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
* thus we don't need tot set it in the LLRs normalization
*/
if (q->llr_is_8bit) {
2021-03-19 03:45:56 -07:00
srsran_demod_soft_demodulate_b(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], cfg->grant.nof_re);
} else {
2021-03-19 03:45:56 -07:00
srsran_demod_soft_demodulate_s(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], cfg->grant.nof_re);
}
if (cfg->meas_evm_en && q->evm_buffer[codeword_idx]) {
if (q->llr_is_8bit) {
2021-03-19 03:45:56 -07:00
data[tb_idx].evm = srsran_evm_run_b(q->evm_buffer[codeword_idx],
&q->mod[mcs->mod],
q->d[codeword_idx],
q->e[codeword_idx],
cfg->grant.tb[tb_idx].nof_bits);
} else {
2021-03-19 03:45:56 -07:00
data[tb_idx].evm = srsran_evm_run_s(q->evm_buffer[codeword_idx],
&q->mod[mcs->mod],
q->d[codeword_idx],
q->e[codeword_idx],
cfg->grant.tb[tb_idx].nof_bits);
}
} else {
data[tb_idx].evm = NAN;
}
2017-09-05 06:26:36 -07:00
/* Bit scrambling */
if (q->llr_is_8bit) {
2021-03-19 03:45:56 -07:00
srsran_sequence_pdsch_apply_c(q->e[codeword_idx],
2021-02-16 10:02:47 -08:00
q->e[codeword_idx],
cfg->rnti,
codeword_idx,
2021-03-19 03:45:56 -07:00
2 * (sf->tti % SRSRAN_NOF_SF_X_FRAME),
2021-02-16 10:02:47 -08:00
q->cell.id,
cfg->grant.tb[tb_idx].nof_bits);
} else {
2021-03-19 03:45:56 -07:00
srsran_sequence_pdsch_apply_s(q->e[codeword_idx],
2021-02-16 10:02:47 -08:00
q->e[codeword_idx],
cfg->rnti,
codeword_idx,
2021-03-19 03:45:56 -07:00
2 * (sf->tti % SRSRAN_NOF_SF_X_FRAME),
2021-02-16 10:02:47 -08:00
q->cell.id,
cfg->grant.tb[tb_idx].nof_bits);
}
2019-04-23 01:53:11 -07:00
if (cfg->csi_enable) {
csi_correction(q, cfg, codeword_idx, tb_idx, q->e[codeword_idx]);
}
2017-09-06 06:25:12 -07:00
/* Return */
2021-03-19 03:45:56 -07:00
ret = srsran_dlsch_decode2(dl_sch, cfg, q->e[codeword_idx], data[tb_idx].payload, tb_idx, nof_layers);
2017-09-26 05:48:59 -07:00
2021-03-19 03:45:56 -07:00
if (ret == SRSRAN_SUCCESS) {
2017-09-06 06:25:12 -07:00
*ack = true;
2021-03-19 03:45:56 -07:00
} else if (ret == SRSRAN_ERROR) {
2017-09-06 06:25:12 -07:00
*ack = false;
2021-03-19 03:45:56 -07:00
ret = SRSRAN_SUCCESS;
} else if (ret == SRSRAN_ERROR_INVALID_INPUTS) {
*ack = false;
2021-03-19 03:45:56 -07:00
ret = SRSRAN_ERROR;
2017-09-06 06:25:12 -07:00
}
} else {
ERROR("Invalid parameters in TB%d &softbuffer=%p &data=%p &ack=%p, nbits=%d, nof_re=%d",
2019-04-23 01:53:11 -07:00
codeword_idx,
softbuffer,
(void*)data,
ack,
cfg->grant.tb[tb_idx].nof_bits,
cfg->grant.nof_re);
2017-09-05 06:26:36 -07:00
}
2017-09-06 06:25:12 -07:00
return ret;
2017-09-05 06:26:36 -07:00
}
2021-03-19 03:45:56 -07:00
static void* srsran_pdsch_decode_thread(void* arg)
{
2021-03-19 03:45:56 -07:00
srsran_pdsch_coworker_t* q = (srsran_pdsch_coworker_t*)arg;
2018-06-06 07:59:00 -07:00
INFO("[PDSCH Coworker] waiting for data");
2018-06-06 07:59:00 -07:00
sem_wait(&q->start);
while (!q->quit) {
2021-03-19 03:45:56 -07:00
q->ret_status = srsran_pdsch_codeword_decode(q->pdsch_ptr, q->sf, q->cfg, &q->dl_sch, q->data, q->tb_idx, q->ack);
2018-06-06 07:59:00 -07:00
/* Post finish semaphore */
sem_post(&q->finish);
/* Wait for next loop */
sem_wait(&q->start);
}
2018-06-11 04:12:46 -07:00
sem_post(&q->finish);
2018-06-06 07:59:00 -07:00
pthread_exit(NULL);
return q;
}
/** Decodes the PDSCH from the received symbols
*/
2021-03-19 03:45:56 -07:00
int srsran_pdsch_decode(srsran_pdsch_t* q,
srsran_dl_sf_cfg_t* sf,
srsran_pdsch_cfg_t* cfg,
srsran_chest_dl_res_t* channel,
cf_t* sf_symbols[SRSRAN_MAX_PORTS],
srsran_pdsch_res_t data[SRSRAN_MAX_CODEWORDS])
{
2014-06-17 07:32:19 -07:00
/* Set pointers for layermapping & precoding */
2017-09-05 06:26:36 -07:00
uint32_t i;
cf_t** x;
2017-09-05 06:26:36 -07:00
2019-04-23 01:53:11 -07:00
if (q != NULL && sf_symbols != NULL && data != NULL && cfg != NULL) {
struct timeval t[3];
if (cfg->meas_time_en) {
gettimeofday(&t[1], NULL);
}
uint32_t nof_tb = cfg->grant.nof_tb;
float pdsch_scaling = 1.0f;
if (cfg->power_scale) {
float rho_a = apply_power_allocation(q, cfg, sf_symbols);
if (rho_a != 0.0f && isnormal(rho_a)) {
pdsch_scaling = rho_a;
}
}
2019-04-23 01:53:11 -07:00
if (cfg->max_nof_iterations) {
2021-03-19 03:45:56 -07:00
srsran_sch_set_max_noi(&q->dl_sch, cfg->max_nof_iterations);
2019-04-23 01:53:11 -07:00
}
2021-03-19 03:45:56 -07:00
float noise_estimate = cfg->decoder_type == SRSRAN_MIMO_DECODER_ZF ? 0 : channel->noise_estimate;
2019-04-23 01:53:11 -07:00
INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d, mod=%s, nof_layers=%d, nof_tb=%d",
2019-04-23 01:53:11 -07:00
sf->tti % 10,
cfg->rnti,
cfg->grant.nof_re,
cfg->grant.nof_prb,
2021-03-19 03:45:56 -07:00
srsran_mod_string(cfg->grant.tb[0].mod),
2019-04-23 01:53:11 -07:00
cfg->grant.nof_layers,
nof_tb);
2017-09-05 06:26:36 -07:00
// Extract Symbols and Channel Estimates
2021-03-19 03:45:56 -07:00
uint32_t lstart = SRSRAN_NOF_CTRL_SYMBOLS(q->cell, sf->cfi);
for (int j = 0; j < q->nof_rx_antennas; j++) {
2021-03-19 03:45:56 -07:00
int n = srsran_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, lstart, sf->tti % 10);
2019-04-23 01:53:11 -07:00
if (n != cfg->grant.nof_re) {
ERROR("Error expecting %d symbols but got %d", cfg->grant.nof_re, n);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR;
}
2017-09-05 06:26:36 -07:00
for (i = 0; i < q->cell.nof_ports; i++) {
2021-03-19 03:45:56 -07:00
n = srsran_pdsch_get(q, channel->ce[i][j], q->ce[i][j], &cfg->grant, lstart, sf->tti % 10);
2019-04-23 01:53:11 -07:00
if (n != cfg->grant.nof_re) {
ERROR("Error expecting %d symbols but got %d", cfg->grant.nof_re, n);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR;
}
2017-09-05 06:26:36 -07:00
}
2015-03-02 02:11:44 -08:00
}
2017-09-05 06:26:36 -07:00
2021-03-19 03:45:56 -07:00
if (cfg->grant.nof_layers == 0 || cfg->grant.nof_layers > SRSRAN_MAX_LAYERS) {
ERROR("PDSCH Number of layers (%d) is out-of-bounds", cfg->grant.nof_layers);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR_OUT_OF_BOUNDS;
2020-09-07 06:15:46 -07:00
}
2017-09-05 06:26:36 -07:00
// Prepare layers
2021-03-19 03:45:56 -07:00
int nof_symbols[SRSRAN_MAX_CODEWORDS];
2019-04-23 01:53:11 -07:00
nof_symbols[0] = cfg->grant.nof_re * nof_tb / cfg->grant.nof_layers;
nof_symbols[1] = cfg->grant.nof_re * nof_tb / cfg->grant.nof_layers;
2017-09-05 06:26:36 -07:00
2019-04-23 01:53:11 -07:00
if (cfg->grant.nof_layers == nof_tb) {
2017-09-05 06:26:36 -07:00
/* Skip layer demap */
x = q->d;
} else {
2017-09-05 06:26:36 -07:00
/* number of layers equals number of ports */
x = q->x;
2017-11-21 01:14:09 -08:00
}
2017-09-05 06:26:36 -07:00
// Pre-decoder
2019-04-23 01:53:11 -07:00
uint32_t codebook_idx = nof_tb == 1 ? cfg->grant.pmi : (cfg->grant.pmi + 1);
2021-03-19 03:45:56 -07:00
if (srsran_predecoding_type(q->symbols,
2019-04-23 01:53:11 -07:00
q->ce,
x,
q->csi,
q->nof_rx_antennas,
q->cell.nof_ports,
cfg->grant.nof_layers,
codebook_idx,
cfg->grant.nof_re,
cfg->grant.tx_scheme,
pdsch_scaling,
noise_estimate) < 0) {
ERROR("Error predecoding");
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR;
}
2017-09-05 06:26:36 -07:00
// Layer demapping only if necessary
2019-04-23 01:53:11 -07:00
if (cfg->grant.nof_layers != nof_tb) {
2021-03-19 03:45:56 -07:00
srsran_layerdemap_type(x, q->d, cfg->grant.nof_layers, nof_tb, nof_symbols[0], nof_symbols, cfg->grant.tx_scheme);
2017-09-05 06:26:36 -07:00
}
/* Codeword decoding: Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */
2021-03-19 03:45:56 -07:00
for (uint32_t tb_idx = 0; tb_idx < SRSRAN_MAX_TB; tb_idx++) {
/* Decode only if transport block is enabled and the default ACK is not true */
2019-04-23 01:53:11 -07:00
if (cfg->grant.tb[tb_idx].enabled) {
if (!data[tb_idx].crc) {
2021-03-19 03:45:56 -07:00
int ret = SRSRAN_SUCCESS;
2019-04-23 01:53:11 -07:00
if (cfg->grant.nof_tb > 1 && tb_idx == 0 && q->coworker_ptr) {
2021-03-19 03:45:56 -07:00
srsran_pdsch_coworker_t* h = (srsran_pdsch_coworker_t*)q->coworker_ptr;
2018-06-06 07:59:00 -07:00
h->pdsch_ptr = q;
h->cfg = cfg;
2019-04-23 01:53:11 -07:00
h->sf = sf;
h->data = &data[tb_idx];
h->tb_idx = tb_idx;
2019-04-23 01:53:11 -07:00
h->ack = &data[tb_idx].crc;
2018-06-06 07:59:00 -07:00
h->dl_sch.max_iterations = q->dl_sch.max_iterations;
h->started = true;
2018-06-06 07:59:00 -07:00
sem_post(&h->start);
} else {
2021-03-19 03:45:56 -07:00
ret = srsran_pdsch_codeword_decode(q, sf, cfg, &q->dl_sch, data, tb_idx, &data[tb_idx].crc);
2019-04-23 01:53:11 -07:00
2021-03-19 03:45:56 -07:00
data[tb_idx].avg_iterations_block = srsran_sch_last_noi(&q->dl_sch);
2018-06-06 07:59:00 -07:00
}
2017-09-06 06:25:12 -07:00
/* Check if there has been any execution error */
if (ret) {
2018-06-11 04:12:46 -07:00
/* Do Nothing */
}
2017-09-06 06:25:12 -07:00
}
}
}
2018-06-11 04:12:46 -07:00
if (q->coworker_ptr) {
2021-03-19 03:45:56 -07:00
srsran_pdsch_coworker_t* h = (srsran_pdsch_coworker_t*)q->coworker_ptr;
2018-06-11 04:12:46 -07:00
if (h->started) {
int err = sem_wait(&h->finish);
if (err) {
2019-04-23 01:53:11 -07:00
printf("SCH coworker: %s (nof_tb=%d)\n", strerror(errno), cfg->grant.nof_tb);
2018-06-11 04:12:46 -07:00
}
if (h->ret_status) {
ERROR("PDSCH Coworker Decoder: Error decoding");
}
2021-03-19 03:45:56 -07:00
data[h->tb_idx].avg_iterations_block = srsran_sch_last_noi(&q->dl_sch);
2019-04-23 01:53:11 -07:00
h->started = false;
2018-06-06 07:59:00 -07:00
}
}
2019-04-23 01:53:11 -07:00
pdsch_decode_debug(q, cfg, sf_symbols, channel->ce);
if (cfg->meas_time_en) {
gettimeofday(&t[2], NULL);
get_time_interval(t);
cfg->meas_time_value = t[0].tv_usec;
}
2017-09-05 06:26:36 -07:00
if (cfg->meas_evm_en) {
2021-03-19 03:45:56 -07:00
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (cfg->grant.tb[i].enabled && !isnan(data[i].evm)) {
2021-03-19 03:45:56 -07:00
q->avg_evm = SRSRAN_VEC_EMA(data[i].evm, q->avg_evm, 0.1);
}
}
}
2021-03-19 03:45:56 -07:00
return SRSRAN_SUCCESS;
2017-09-05 06:26:36 -07:00
} else {
ERROR("Invalid inputs");
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR_INVALID_INPUTS;
2017-09-05 06:26:36 -07:00
}
}
2021-03-19 03:45:56 -07:00
static int srsran_pdsch_codeword_encode(srsran_pdsch_t* q,
srsran_dl_sf_cfg_t* sf,
srsran_pdsch_cfg_t* cfg,
srsran_softbuffer_tx_t* softbuffer,
2019-04-23 01:53:11 -07:00
uint8_t* data,
uint32_t tb_idx,
uint32_t nof_layers)
{
2021-03-19 03:45:56 -07:00
srsran_ra_tb_t* mcs = &cfg->grant.tb[tb_idx];
2019-04-23 01:53:11 -07:00
uint32_t rv = cfg->grant.tb[tb_idx].rv;
uint32_t codeword_idx = cfg->grant.tb[tb_idx].cw_idx;
if (!softbuffer) {
ERROR("Error encoding (TB%d -> CW%d), softbuffer=NULL", tb_idx, codeword_idx);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR_INVALID_INPUTS;
2019-04-23 01:53:11 -07:00
}
if (cfg->grant.tb[tb_idx].enabled) {
2021-03-19 03:45:56 -07:00
if (cfg->rnti != SRSRAN_SIRNTI) {
INFO("Encoding PDSCH SF: %d (TB%d -> CW%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d",
2019-04-23 01:53:11 -07:00
sf->tti % 10,
tb_idx,
codeword_idx,
2021-03-19 03:45:56 -07:00
srsran_mod_string(mcs->mod),
2019-04-23 01:53:11 -07:00
mcs->tbs,
cfg->grant.nof_re,
cfg->grant.tb[tb_idx].nof_bits,
rv);
2017-09-05 06:26:36 -07:00
}
2019-04-23 01:53:11 -07:00
/* Channel coding */
2021-03-19 03:45:56 -07:00
if (srsran_dlsch_encode2(&q->dl_sch, cfg, data, q->e[codeword_idx], tb_idx, nof_layers)) {
2019-04-23 01:53:11 -07:00
ERROR("Error encoding (TB%d -> CW%d)", tb_idx, codeword_idx);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR;
}
2019-04-23 01:53:11 -07:00
/* Bit scrambling */
2021-03-19 03:45:56 -07:00
srsran_sequence_pdsch_apply_pack((uint8_t*)q->e[codeword_idx],
2021-02-16 10:02:47 -08:00
(uint8_t*)q->e[codeword_idx],
cfg->rnti,
codeword_idx,
2021-03-19 03:45:56 -07:00
2 * (sf->tti % SRSRAN_NOF_SF_X_FRAME),
2021-02-16 10:02:47 -08:00
q->cell.id,
cfg->grant.tb[tb_idx].nof_bits);
2019-04-23 01:53:11 -07:00
/* Bit mapping */
2021-03-19 03:45:56 -07:00
srsran_mod_modulate_bytes(
2019-04-23 01:53:11 -07:00
&q->mod[mcs->mod], (uint8_t*)q->e[codeword_idx], q->d[codeword_idx], cfg->grant.tb[tb_idx].nof_bits);
} else {
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR_INVALID_INPUTS;
}
2017-09-05 06:26:36 -07:00
2021-03-19 03:45:56 -07:00
return SRSRAN_SUCCESS;
2017-09-05 06:26:36 -07:00
}
2021-03-19 03:45:56 -07:00
int srsran_pdsch_encode(srsran_pdsch_t* q,
srsran_dl_sf_cfg_t* sf,
srsran_pdsch_cfg_t* cfg,
uint8_t* data[SRSRAN_MAX_CODEWORDS],
cf_t* sf_symbols[SRSRAN_MAX_PORTS])
{
2014-06-17 07:32:19 -07:00
int i;
/* Set pointers for layermapping & precoding */
2021-03-19 03:45:56 -07:00
cf_t* x[SRSRAN_MAX_LAYERS];
int ret = SRSRAN_ERROR_INVALID_INPUTS;
2017-09-05 06:26:36 -07:00
2019-04-23 01:53:11 -07:00
if (q != NULL && cfg != NULL) {
struct timeval t[3];
if (cfg->meas_time_en) {
gettimeofday(&t[1], NULL);
}
2019-04-23 01:53:11 -07:00
uint32_t nof_tb = cfg->grant.nof_tb;
2014-06-17 07:32:19 -07:00
2017-09-05 06:26:36 -07:00
for (i = 0; i < q->cell.nof_ports; i++) {
2015-03-02 02:11:44 -08:00
if (sf_symbols[i] == NULL) {
ERROR("Error NULL pointer in sf_symbols[%d]", i);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR_INVALID_INPUTS;
}
2015-03-02 02:11:44 -08:00
}
2017-09-05 06:26:36 -07:00
/* If both transport block size is zero return error */
if (!nof_tb) {
ERROR("Error number of TB is zero");
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR_INVALID_INPUTS;
2015-03-02 02:11:44 -08:00
}
2014-06-17 07:32:19 -07:00
if (cfg->grant.nof_re > q->max_re) {
ERROR("Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)",
2019-04-23 01:53:11 -07:00
cfg->grant.nof_re,
q->max_re,
q->cell.nof_prb);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR_INVALID_INPUTS;
2015-03-02 02:11:44 -08:00
}
2014-06-17 07:32:19 -07:00
2019-04-23 01:53:11 -07:00
float rho_a = apply_power_allocation(q, cfg, sf_symbols);
/* Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */
2021-03-19 03:45:56 -07:00
for (uint32_t tb_idx = 0; tb_idx < SRSRAN_MAX_TB; tb_idx++) {
2019-04-23 01:53:11 -07:00
if (cfg->grant.tb[tb_idx].enabled) {
2021-03-19 03:45:56 -07:00
ret |= srsran_pdsch_codeword_encode(
2019-04-23 01:53:11 -07:00
q, sf, cfg, cfg->softbuffers.tx[tb_idx], data[tb_idx], tb_idx, cfg->grant.nof_layers);
}
2015-03-02 02:11:44 -08:00
}
/* Set scaling configured by Power Allocation */
float scaling = 1.0f;
2019-04-23 01:53:11 -07:00
if (rho_a != 0.0f) {
scaling = rho_a;
}
2021-03-19 03:45:56 -07:00
if (cfg->rnti != SRSRAN_SIRNTI) {
INFO("Encoding PDSCH SF: %d rho_a=%f, nof_ports=%d, nof_layers=%d, nof_tb=%d, pmi=%d, tx_scheme=%s",
2019-04-23 01:53:11 -07:00
sf->tti % 10,
rho_a,
q->cell.nof_ports,
cfg->grant.nof_layers,
nof_tb,
cfg->grant.pmi,
2021-03-19 03:45:56 -07:00
srsran_mimotype2str(cfg->grant.tx_scheme));
}
2017-09-05 06:26:36 -07:00
// Layer mapping & precode if necessary
if (q->cell.nof_ports > 1) {
int nof_symbols;
/* If number of layers is equal to transport blocks (codewords) skip layer mapping */
2019-04-23 01:53:11 -07:00
if (cfg->grant.nof_layers == nof_tb) {
for (i = 0; i < cfg->grant.nof_layers; i++) {
2017-09-05 06:26:36 -07:00
x[i] = q->d[i];
}
2019-04-23 01:53:11 -07:00
nof_symbols = cfg->grant.nof_re;
2017-09-05 06:26:36 -07:00
} else {
/* Initialise layer map pointers */
2019-04-23 01:53:11 -07:00
for (i = 0; i < cfg->grant.nof_layers; i++) {
2017-09-05 06:26:36 -07:00
x[i] = q->x[i];
}
2021-03-19 03:45:56 -07:00
memset(&x[cfg->grant.nof_layers], 0, sizeof(cf_t*) * (SRSRAN_MAX_LAYERS - cfg->grant.nof_layers));
2019-04-23 01:53:11 -07:00
2021-03-19 03:45:56 -07:00
nof_symbols = srsran_layermap_type(q->d,
2019-04-23 01:53:11 -07:00
x,
nof_tb,
cfg->grant.nof_layers,
2021-03-19 03:45:56 -07:00
(int[SRSRAN_MAX_CODEWORDS]){cfg->grant.nof_re, cfg->grant.nof_re},
2019-04-23 01:53:11 -07:00
cfg->grant.tx_scheme);
2017-09-05 06:26:36 -07:00
}
2017-09-05 06:26:36 -07:00
/* Precode */
2019-04-23 01:53:11 -07:00
uint32_t codebook_idx = nof_tb == 1 ? cfg->grant.pmi : (cfg->grant.pmi + 1);
2021-03-19 03:45:56 -07:00
srsran_precoding_type(x,
2019-04-23 01:53:11 -07:00
q->symbols,
cfg->grant.nof_layers,
q->cell.nof_ports,
codebook_idx,
nof_symbols,
scaling,
cfg->grant.tx_scheme);
} else {
if (scaling == 1.0f) {
2019-04-23 01:53:11 -07:00
memcpy(q->symbols[0], q->d[0], cfg->grant.nof_re * sizeof(cf_t));
} else {
2021-03-19 03:45:56 -07:00
srsran_vec_sc_prod_cfc(q->d[0], scaling, q->symbols[0], cfg->grant.nof_re);
}
}
2015-03-02 02:11:44 -08:00
/* mapping to resource elements */
2021-03-19 03:45:56 -07:00
uint32_t lstart = SRSRAN_NOF_CTRL_SYMBOLS(q->cell, sf->cfi);
2015-03-02 02:11:44 -08:00
for (i = 0; i < q->cell.nof_ports; i++) {
2021-03-19 03:45:56 -07:00
srsran_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, lstart, sf->tti % 10);
2019-04-23 01:53:11 -07:00
}
if (cfg->meas_time_en) {
gettimeofday(&t[2], NULL);
get_time_interval(t);
cfg->meas_time_value = t[0].tv_usec;
2015-03-02 02:11:44 -08:00
}
2017-09-05 06:26:36 -07:00
2021-03-19 03:45:56 -07:00
ret = SRSRAN_SUCCESS;
2017-09-05 06:26:36 -07:00
}
return ret;
}
2021-03-19 03:45:56 -07:00
int srsran_pdsch_select_pmi(srsran_pdsch_t* q,
srsran_chest_dl_res_t* channel,
2019-04-23 01:53:11 -07:00
uint32_t nof_layers,
uint32_t* best_pmi,
2021-03-19 03:45:56 -07:00
float sinr[SRSRAN_MAX_CODEBOOKS])
2019-04-23 01:53:11 -07:00
{
2021-03-19 03:45:56 -07:00
uint32_t nof_ce = SRSRAN_NOF_RE(q->cell);
2019-04-23 01:53:11 -07:00
uint32_t pmi = 0;
2017-09-05 06:26:36 -07:00
2021-03-19 03:45:56 -07:00
if (srsran_precoding_pmi_select(channel->ce, nof_ce, channel->noise_estimate, nof_layers, &pmi, sinr) < 0) {
2019-04-23 01:53:11 -07:00
ERROR("PMI Select for %d layers", nof_layers);
2021-03-19 03:45:56 -07:00
return SRSRAN_ERROR;
}
2019-04-23 01:53:11 -07:00
if (best_pmi) {
*best_pmi = pmi;
}
2021-03-19 03:45:56 -07:00
return SRSRAN_SUCCESS;
2019-04-23 01:53:11 -07:00
}
2018-06-06 07:59:00 -07:00
2021-03-19 03:45:56 -07:00
int srsran_pdsch_compute_cn(srsran_pdsch_t* q, srsran_chest_dl_res_t* channel, float* cn)
2019-04-23 01:53:11 -07:00
{
2021-03-19 03:45:56 -07:00
return srsran_precoding_cn(channel->ce, q->cell.nof_ports, q->nof_rx_antennas, SRSRAN_NOF_RE(q->cell), cn);
2019-04-23 01:53:11 -07:00
}
2018-06-06 07:59:00 -07:00
2021-03-19 03:45:56 -07:00
uint32_t srsran_pdsch_grant_rx_info(srsran_pdsch_grant_t* grant,
srsran_pdsch_res_t res[SRSRAN_MAX_CODEWORDS],
2019-04-23 01:53:11 -07:00
char* str,
uint32_t str_len)
{
2021-03-19 03:45:56 -07:00
uint32_t len = srsran_ra_dl_info(grant, str, str_len);
2018-06-06 07:59:00 -07:00
len = srsran_print_check(str, str_len, len, ", crc={");
2021-03-19 03:45:56 -07:00
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
2019-04-23 01:53:11 -07:00
if (grant->tb[i].enabled) {
2021-03-19 03:45:56 -07:00
len = srsran_print_check(str, str_len, len, "%s", res[i].crc ? "OK" : "KO");
if (i < SRSRAN_MAX_CODEWORDS - 1) {
2019-04-23 01:53:11 -07:00
if (grant->tb[i + 1].enabled) {
len = srsran_print_check(str, str_len, len, "/");
2019-04-23 01:53:11 -07:00
}
}
2018-06-06 07:59:00 -07:00
}
}
len = srsran_print_check(str, str_len, len, "}");
2018-06-06 07:59:00 -07:00
2019-04-23 01:53:11 -07:00
// Average iterations between nof TB and divide by 2 to get full decoder iterations
2021-03-19 03:45:56 -07:00
len = srsran_print_check(
2019-04-23 01:53:11 -07:00
str, str_len, len, ", it=%.1f", (res[0].avg_iterations_block + res[1].avg_iterations_block) / grant->nof_tb / 2);
return len;
2018-06-06 07:59:00 -07:00
}
2019-04-23 01:53:11 -07:00
uint32_t
2021-03-19 03:45:56 -07:00
srsran_pdsch_rx_info(srsran_pdsch_cfg_t* cfg, srsran_pdsch_res_t res[SRSRAN_MAX_CODEWORDS], char* str, uint32_t str_len)
2019-04-23 01:53:11 -07:00
{
2021-03-19 03:45:56 -07:00
uint32_t len = srsran_print_check(str, str_len, 0, "rnti=0x%x", cfg->rnti);
len += srsran_pdsch_grant_rx_info(&cfg->grant, res, &str[len], str_len - len);
2019-04-23 01:53:11 -07:00
if (cfg->meas_evm_en) {
len = srsran_print_check(str, str_len, len, ", evm={");
2021-03-19 03:45:56 -07:00
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (cfg->grant.tb[i].enabled && !isnan(res[i].evm)) {
2021-03-19 03:45:56 -07:00
len = srsran_print_check(str, str_len, len, "%.2f", res[i].evm);
if (i < SRSRAN_MAX_CODEWORDS - 1) {
if (cfg->grant.tb[i + 1].enabled) {
2021-03-19 03:45:56 -07:00
len = srsran_print_check(str, str_len, len, "/", 0);
}
}
}
}
len = srsran_print_check(str, str_len, len, "}");
}
2019-04-23 01:53:11 -07:00
if (cfg->meas_time_en) {
2021-03-19 03:45:56 -07:00
len = srsran_print_check(str, str_len, len, ", t=%d us", cfg->meas_time_value);
2019-04-23 01:53:11 -07:00
}
return len;
}
2021-03-19 03:45:56 -07:00
uint32_t srsran_pdsch_tx_info(srsran_pdsch_cfg_t* cfg, char* str, uint32_t str_len)
2019-04-23 01:53:11 -07:00
{
2021-03-19 03:45:56 -07:00
uint32_t len = srsran_print_check(str, str_len, 0, "rnti=0x%x", cfg->rnti);
len += srsran_ra_dl_info(&cfg->grant, &str[len], str_len);
2019-04-23 01:53:11 -07:00
if (cfg->meas_time_en) {
2021-03-19 03:45:56 -07:00
len = srsran_print_check(str, str_len, len, ", t=%d us", cfg->meas_time_value);
2019-04-23 01:53:11 -07:00
}
return len;
}