mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
14 KiB
C
267 lines
14 KiB
C
4 years ago
|
/**
|
||
5 years ago
|
*
|
||
4 years ago
|
* \section COPYRIGHT
|
||
5 years ago
|
*
|
||
4 years ago
|
* Copyright 2013-2021 Software Radio Systems Limited
|
||
5 years ago
|
*
|
||
4 years ago
|
* 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.
|
||
5 years ago
|
*
|
||
|
*/
|
||
|
|
||
4 years ago
|
#ifndef SRSRAN_EVM_H_
|
||
|
#define SRSRAN_EVM_H_
|
||
5 years ago
|
|
||
4 years ago
|
#include "srsran/phy/modem/mod.h"
|
||
|
#include "srsran/phy/modem/modem_table.h"
|
||
|
#include "srsran/phy/phch/ra.h"
|
||
|
#include "srsran/phy/utils/debug.h"
|
||
|
#include "srsran/phy/utils/vector.h"
|
||
5 years ago
|
|
||
4 years ago
|
/** @struct srsran_evm_buffer_t
|
||
5 years ago
|
* This structure carries the necessary temporary data required for calculating the EVM.
|
||
|
*
|
||
|
* @var max_bits maximum of bits which can support
|
||
|
* @var hard_bits vector that stores hard bits after decision
|
||
|
* @var symbols vector that stores the modulated symbols from the hard bits
|
||
|
*/
|
||
|
typedef struct {
|
||
|
uint32_t max_bits;
|
||
|
uint8_t* hard_bits;
|
||
|
cf_t* symbols;
|
||
4 years ago
|
} srsran_evm_buffer_t;
|
||
5 years ago
|
|
||
|
/**
|
||
|
* Allocates the EVM calculation buffer
|
||
|
* @param nof_prb that provides the maximum number of bits
|
||
|
* @return EVM buffer pointer
|
||
|
*/
|
||
4 years ago
|
static inline srsran_evm_buffer_t* srsran_evm_buffer_alloc(uint32_t nof_bits)
|
||
5 years ago
|
{
|
||
4 years ago
|
srsran_evm_buffer_t* q = SRSRAN_MEM_ALLOC(srsran_evm_buffer_t, 1);
|
||
5 years ago
|
|
||
|
// Check allocation result and number of PRB
|
||
4 years ago
|
if (!q || !nof_bits) {
|
||
5 years ago
|
ERROR("Malloc");
|
||
|
return q;
|
||
|
}
|
||
|
|
||
|
// Zero memory the buffer fields
|
||
4 years ago
|
SRSRAN_MEM_ZERO(q, srsran_evm_buffer_t, 1);
|
||
5 years ago
|
|
||
|
// Set max number of bits
|
||
4 years ago
|
q->max_bits = nof_bits;
|
||
5 years ago
|
|
||
|
// Allocate hard bits
|
||
4 years ago
|
q->hard_bits = srsran_vec_u8_malloc(q->max_bits);
|
||
5 years ago
|
if (!q->hard_bits) {
|
||
|
ERROR("Malloc");
|
||
|
return q;
|
||
|
}
|
||
|
|
||
|
// Allocate symbols assuming BPSK
|
||
4 years ago
|
q->symbols = srsran_vec_cf_malloc(q->max_bits);
|
||
5 years ago
|
if (!q->symbols) {
|
||
|
ERROR("Malloc");
|
||
|
return q;
|
||
|
}
|
||
|
|
||
|
return q;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Allocates the EVM calculation buffer
|
||
|
* @param nof_prb that provides the maximum number of bits
|
||
|
* @return EVM buffer pointer
|
||
|
*/
|
||
4 years ago
|
static inline void srsran_evm_buffer_resize(srsran_evm_buffer_t* q, uint32_t new_max_bits)
|
||
5 years ago
|
{
|
||
|
// Assert pointer and number of PRB
|
||
4 years ago
|
if (!q || !new_max_bits) {
|
||
5 years ago
|
ERROR("Invalid inputs");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Return if no resize is required
|
||
|
if (q->max_bits >= new_max_bits) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Update with greater value
|
||
|
q->max_bits = new_max_bits;
|
||
|
|
||
|
// Free hard bits if it was allocated
|
||
|
if (q->hard_bits) {
|
||
|
free(q->hard_bits);
|
||
|
}
|
||
|
|
||
|
// Allocate hard bits again
|
||
4 years ago
|
q->hard_bits = srsran_vec_u8_malloc(q->max_bits);
|
||
5 years ago
|
if (!q->hard_bits) {
|
||
|
ERROR("Malloc");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Free symbols if it was allocated
|
||
|
if (q->symbols) {
|
||
|
free(q->symbols);
|
||
|
}
|
||
|
|
||
|
// Allocate symbols again
|
||
4 years ago
|
q->symbols = srsran_vec_cf_malloc(q->max_bits);
|
||
5 years ago
|
if (!q->symbols) {
|
||
|
ERROR("Malloc");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Template for hard decision taking
|
||
|
*/
|
||
5 years ago
|
#define HARD_DECISION(LLR_T, SOFTBITS, HARDBITS, NOF_SOFTBITS) \
|
||
5 years ago
|
do { \
|
||
5 years ago
|
/* Typecasts pointer type to minimum width */ \
|
||
|
uint8_t* ptr = (uint8_t*)SOFTBITS; \
|
||
|
\
|
||
|
/* Big endian compensation, ptr needs to point at the MSB */ \
|
||
|
ptr += sizeof(LLR_T) - 1UL; \
|
||
|
\
|
||
|
for (uint32_t i = 0; i < NOF_SOFTBITS / 8; i++) { \
|
||
|
/* Default mask */ \
|
||
|
uint8_t w = 0xff; \
|
||
|
\
|
||
|
/* For each soft bit, take MSB ad collocate in right position */ \
|
||
|
w ^= (*ptr & 0x80); \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
w ^= (*ptr & 0x80) >> 1; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
w ^= (*ptr & 0x80) >> 2; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
w ^= (*ptr & 0x80) >> 3; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
w ^= (*ptr & 0x80) >> 4; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
w ^= (*ptr & 0x80) >> 5; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
w ^= (*ptr & 0x80) >> 6; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
w ^= (*ptr & 0x80) >> 7; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
5 years ago
|
HARDBITS[i] = w; \
|
||
|
} \
|
||
4 years ago
|
if (NOF_SOFTBITS % 8) { \
|
||
|
uint8_t w = 0xff; \
|
||
|
for (uint32_t i = 0; i < NOF_SOFTBITS % 8; i++) { \
|
||
|
w ^= (*ptr & 0x80) >> i; \
|
||
|
ptr += sizeof(LLR_T); \
|
||
|
} \
|
||
|
HARDBITS[NOF_SOFTBITS / 8] = w; \
|
||
|
} \
|
||
5 years ago
|
} while (false)
|
||
|
|
||
|
/**
|
||
|
* Template RMS EVM calculation for different LLR
|
||
|
*/
|
||
|
#define EVM_RUN_TEMPLATE(LLR_T, SUFFIX) \
|
||
4 years ago
|
static inline float srsran_evm_run_##SUFFIX(srsran_evm_buffer_t* q, \
|
||
|
const srsran_modem_table_t* modem_table, \
|
||
5 years ago
|
const cf_t* symbols, \
|
||
|
const LLR_T* llr, \
|
||
|
uint32_t nof_bits) \
|
||
|
{ \
|
||
|
float evm_rms = NAN; \
|
||
|
\
|
||
|
/* Return NAN if EVM buffers, modem table, LLR, symbols or bits missing*/ \
|
||
|
if (!q || !modem_table || !modem_table->nbits_x_symbol || !llr || !symbols || !nof_bits) { \
|
||
4 years ago
|
ERROR("Invalid inputs %p %p %p %p %d", q, modem_table, llr, symbols, nof_bits); \
|
||
5 years ago
|
return evm_rms; \
|
||
|
} \
|
||
|
\
|
||
|
/* Limit number of bits to the one supported by the buffer */ \
|
||
4 years ago
|
nof_bits = SRSRAN_MIN(q->max_bits, nof_bits); \
|
||
5 years ago
|
\
|
||
|
/* Calculate number of symbols */ \
|
||
|
uint32_t nsymbols = nof_bits / modem_table->nbits_x_symbol; \
|
||
|
\
|
||
|
/* Hard decision */ \
|
||
5 years ago
|
HARD_DECISION(LLR_T, llr, q->hard_bits, nof_bits); \
|
||
5 years ago
|
\
|
||
|
/* Modulate */ \
|
||
4 years ago
|
srsran_mod_modulate_bytes(modem_table, q->hard_bits, q->symbols, nof_bits); \
|
||
5 years ago
|
\
|
||
|
/* Compute symbol difference */ \
|
||
4 years ago
|
srsran_vec_sub_ccc(symbols, q->symbols, q->symbols, nsymbols); \
|
||
5 years ago
|
\
|
||
|
/* Average squares */ \
|
||
4 years ago
|
float evm_pow = srsran_vec_avg_power_cf(q->symbols, nsymbols); \
|
||
5 years ago
|
\
|
||
|
/* Convert measure to RMS */ \
|
||
|
evm_rms = sqrtf(evm_pow); \
|
||
|
\
|
||
|
return evm_rms; \
|
||
|
}
|
||
|
|
||
4 years ago
|
/** @function srsran_evm_run_f
|
||
5 years ago
|
* Calculates the Root Mean Squared EVM given a modulation table, complex symbols, floating point LLR (soft bits) and
|
||
|
* the number of bits.
|
||
|
*
|
||
|
* @param q is the EVM buffers, need to be preallocated
|
||
|
* @param modem_table points at the modulator table
|
||
|
* @param symbols vector carrying the modulated complex symbols
|
||
|
* @param llr softbits
|
||
|
* @param nof_bits number of bits
|
||
|
* @return the measured RMS EVM if no error occurs, otherwise it returns NAN
|
||
|
*/
|
||
|
EVM_RUN_TEMPLATE(float, f)
|
||
|
|
||
4 years ago
|
/** @function srsran_evm_run_s
|
||
5 years ago
|
* Calculates the Root Mean Squared EVM given a modulation table, complex symbols, fixed integer 16 bit LLR (soft bits)
|
||
|
* and the number of bits.
|
||
|
*
|
||
|
* @param q is the EVM buffers, need to be preallocated
|
||
|
* @param modem_table points at the modulator table
|
||
|
* @param symbols vector carrying the modulated complex symbols
|
||
|
* @param llr softbits
|
||
|
* @param nof_bits number of bits
|
||
|
* @return the measured RMS EVM if no error occurs, otherwise it returns NAN
|
||
|
*/
|
||
|
EVM_RUN_TEMPLATE(int16_t, s)
|
||
|
|
||
4 years ago
|
/** @function srsran_evm_run_b
|
||
5 years ago
|
* Calculates the Root Mean Squared EVM given a modulation table, complex symbols, fixed integer 8 bit LLR (soft bits)
|
||
|
* and the number of bits.
|
||
|
*
|
||
|
* @param q is the EVM buffers, need to be preallocated
|
||
|
* @param modem_table points at the modulator table
|
||
|
* @param symbols vector carrying the modulated complex symbols
|
||
|
* @param llr softbits
|
||
|
* @param nof_bits number of bits
|
||
|
* @return the measured RMS EVM if no error occurs, otherwise it returns NAN
|
||
|
*/
|
||
|
EVM_RUN_TEMPLATE(int8_t, b)
|
||
|
|
||
|
#undef EVM_RUN_TEMPLATE
|
||
|
#undef HARD_DECISION
|
||
|
|
||
4 years ago
|
static inline void srsran_evm_free(srsran_evm_buffer_t* q)
|
||
5 years ago
|
{
|
||
|
// Check EVM buffer object exist
|
||
|
if (q) {
|
||
|
// Check hard bits were allocated
|
||
|
if (q->hard_bits) {
|
||
|
free(q->hard_bits);
|
||
|
}
|
||
|
|
||
|
// Check symbols were allocated
|
||
|
if (q->symbols) {
|
||
|
free(q->symbols);
|
||
|
}
|
||
|
|
||
|
// Free buffer object
|
||
|
free(q);
|
||
|
}
|
||
|
}
|
||
|
|
||
4 years ago
|
#endif // SRSRAN_EVM_H_
|