Initial 256QAM Modem and Demodulator

master
Guillem Foreman 6 years ago committed by Xavier Arteaga
parent 4ec22b8353
commit 50edd9a325

@ -243,6 +243,7 @@ typedef enum SRSLTE_API {
SRSLTE_MOD_QPSK,
SRSLTE_MOD_16QAM,
SRSLTE_MOD_64QAM,
SRSLTE_MOD_256QAM,
} srslte_mod_t;
typedef enum {

@ -49,6 +49,10 @@ typedef struct {
cf_t symbol[2];
} qam16_packed_t;
typedef struct {
cf_t symbol[256];
} qam256_packed_t;
typedef struct SRSLTE_API {
cf_t* symbol_table; // bit-to-symbol mapping
uint32_t nsymbols; // number of modulation symbols
@ -58,6 +62,7 @@ typedef struct SRSLTE_API {
bpsk_packed_t *symbol_table_bpsk;
qpsk_packed_t *symbol_table_qpsk;
qam16_packed_t* symbol_table_16qam;
qam256_packed_t* symbol_table_256qam;
}srslte_modem_table_t;

@ -208,6 +208,8 @@ srslte_mod_t srslte_str2mod (char * mod_str) {
return SRSLTE_MOD_16QAM;
} else if (!strcmp(mod_str, "64QAM")) {
return SRSLTE_MOD_64QAM;
} else if (!strcmp(mod_str, "256QAM")) {
return SRSLTE_MOD_256QAM;
} else {
return (srslte_mod_t) SRSLTE_ERROR_INVALID_INPUTS;
}
@ -224,6 +226,8 @@ char *srslte_mod_string(srslte_mod_t mod) {
return "16QAM";
case SRSLTE_MOD_64QAM:
return "64QAM";
case SRSLTE_MOD_256QAM:
return "256QAM";
default:
return "N/A";
}
@ -239,6 +243,8 @@ uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod) {
return 4;
case SRSLTE_MOD_64QAM:
return 6;
case SRSLTE_MOD_256QAM:
return 8;
default:
return 0;
}

@ -54,6 +54,10 @@ int srslte_demod_hard_demodulate(srslte_demod_hard_t* q, cf_t* symbols, uint8_t
hard_qam64_demod(symbols,bits,nsymbols);
nbits=nsymbols*6;
break;
case SRSLTE_MOD_256QAM:
hard_qam256_demod(symbols, bits, nsymbols);
nbits = nsymbols * 8;
break;
}
return nbits;
}

@ -36,10 +36,12 @@ void demod_16qam_lte_s_sse(const cf_t *symbols, short *llr, int nsymbols);
#define SCALE_SHORT_CONV_QPSK 100
#define SCALE_SHORT_CONV_QAM16 400
#define SCALE_SHORT_CONV_QAM64 700
#define SCALE_SHORT_CONV_QAM256 1000
#define SCALE_BYTE_CONV_QPSK 20
#define SCALE_BYTE_CONV_QAM16 30
#define SCALE_BYTE_CONV_QAM64 40
#define SCALE_BYTE_CONV_QAM256 50
void demod_bpsk_lte_b(const cf_t *symbols, int8_t *llr, int nsymbols) {
for (int i=0;i<nsymbols;i++) {
@ -408,6 +410,57 @@ void demod_64qam_lte_b(const cf_t *symbols, int8_t *llr, int nsymbols)
#endif
}
void demod_256qam_lte(const cf_t* symbols, float* llr, int nsymbols)
{
for (int i = 0; i < nsymbols; i++) {
float real = crealf(symbols[i]);
float imag = cimagf(symbols[i]);
llr[8 * i + 0] = -real;
llr[8 * i + 1] = -imag;
llr[8 * i + 2] = fabsf(real) - 8 / sqrt(170);
llr[8 * i + 3] = fabsf(imag) - 8 / sqrt(170);
llr[8 * i + 4] = fabsf(llr[8 * i + 2]) - 4 / sqrt(170);
llr[8 * i + 5] = fabsf(llr[8 * i + 3]) - 4 / sqrt(170);
llr[8 * i + 6] = fabsf(llr[8 * i + 4]) - 2 / sqrt(170);
llr[8 * i + 7] = fabsf(llr[8 * i + 5]) - 2 / sqrt(170);
}
}
void demod_256qam_lte_b(const cf_t* symbols, int8_t* llr, int nsymbols)
{
for (int i = 0; i < nsymbols; i++) {
float real = SCALE_BYTE_CONV_QAM256 * crealf(symbols[i]);
float imag = SCALE_BYTE_CONV_QAM256 * cimagf(symbols[i]);
llr[8 * i + 0] = -real;
llr[8 * i + 1] = -imag;
llr[8 * i + 2] = fabsf(real) - SCALE_BYTE_CONV_QAM256 * 8 / sqrt(170);
llr[8 * i + 3] = fabsf(imag) - SCALE_BYTE_CONV_QAM256 * 8 / sqrt(170);
llr[8 * i + 4] = fabsf(llr[8 * i + 2]) - SCALE_BYTE_CONV_QAM256 * 4 / sqrt(170);
llr[8 * i + 5] = fabsf(llr[8 * i + 3]) - SCALE_BYTE_CONV_QAM256 * 4 / sqrt(170);
llr[8 * i + 6] = fabsf(llr[8 * i + 4]) - SCALE_BYTE_CONV_QAM256 * 2 / sqrt(170);
llr[8 * i + 7] = fabsf(llr[8 * i + 5]) - SCALE_BYTE_CONV_QAM256 * 2 / sqrt(170);
}
}
void demod_256qam_lte_s(const cf_t* symbols, short* llr, int nsymbols)
{
for (int i = 0; i < nsymbols; i++) {
float real = SCALE_SHORT_CONV_QAM256 * crealf(symbols[i]);
float imag = SCALE_SHORT_CONV_QAM256 * cimagf(symbols[i]);
llr[8 * i + 0] = -real;
llr[8 * i + 1] = -imag;
llr[8 * i + 2] = fabsf(real) - SCALE_SHORT_CONV_QAM256 * 8 / sqrt(170);
llr[8 * i + 3] = fabsf(imag) - SCALE_SHORT_CONV_QAM256 * 8 / sqrt(170);
llr[8 * i + 4] = fabsf(llr[8 * i + 2]) - SCALE_SHORT_CONV_QAM256 * 4 / sqrt(170);
llr[8 * i + 5] = fabsf(llr[8 * i + 3]) - SCALE_SHORT_CONV_QAM256 * 4 / sqrt(170);
llr[8 * i + 6] = fabsf(llr[8 * i + 4]) - SCALE_SHORT_CONV_QAM256 * 2 / sqrt(170);
llr[8 * i + 7] = fabsf(llr[8 * i + 5]) - SCALE_SHORT_CONV_QAM256 * 2 / sqrt(170);
}
}
int srslte_demod_soft_demodulate(srslte_mod_t modulation, const cf_t* symbols, float* llr, int nsymbols) {
switch(modulation) {
case SRSLTE_MOD_BPSK:
@ -422,6 +475,9 @@ int srslte_demod_soft_demodulate(srslte_mod_t modulation, const cf_t* symbols, f
case SRSLTE_MOD_64QAM:
demod_64qam_lte(symbols, llr, nsymbols);
break;
case SRSLTE_MOD_256QAM:
demod_256qam_lte(symbols, llr, nsymbols);
break;
default:
ERROR("Invalid modulation %d\n", modulation);
return -1;
@ -443,6 +499,9 @@ int srslte_demod_soft_demodulate_s(srslte_mod_t modulation, const cf_t* symbols,
case SRSLTE_MOD_64QAM:
demod_64qam_lte_s(symbols, llr, nsymbols);
break;
case SRSLTE_MOD_256QAM:
demod_256qam_lte_s(symbols, llr, nsymbols);
break;
default:
ERROR("Invalid modulation %d\n", modulation);
return -1;
@ -464,6 +523,9 @@ int srslte_demod_soft_demodulate_b(srslte_mod_t modulation, const cf_t* symbols,
case SRSLTE_MOD_64QAM:
demod_64qam_lte_b(symbols, llr, nsymbols);
break;
case SRSLTE_MOD_256QAM:
demod_256qam_lte_b(symbols, llr, nsymbols);
break;
default:
ERROR("Invalid modulation %d\n", modulation);
return -1;

@ -197,3 +197,91 @@ inline void hard_qam64_demod(const cf_t* in, uint8_t* out, uint32_t N)
}
}
}
inline void hard_qam256_demod(const cf_t* in, uint8_t* out, uint32_t N)
{
uint32_t s;
for (s = 0; s < N; s++) {
if (__real__ in[s] > 0) {
out[8 * s] = 0x0;
} else {
out[8 * s] = 0x1;
}
if ((__real__ in[s] > QAM256_THRESHOLD_7) || (__real__ in[s] < -QAM256_THRESHOLD_7)) {
out[8 * s + 2] = 0x1;
out[8 * s + 4] = 0x1;
out[8 * s + 6] = 0x1;
} else if ((__real__ in[s] > QAM256_THRESHOLD_6) || (__real__ in[s] < -QAM256_THRESHOLD_6)) {
out[6 * s + 2] = 0x1;
out[6 * s + 4] = 0x1;
out[8 * s + 6] = 0x0;
} else if ((__real__ in[s] > QAM256_THRESHOLD_5) || (__real__ in[s] < -QAM256_THRESHOLD_5)) {
out[6 * s + 2] = 0x1;
out[6 * s + 4] = 0x0;
out[8 * s + 6] = 0x0;
} else if ((__real__ in[s] > QAM256_THRESHOLD_4) || (__real__ in[s] < -QAM256_THRESHOLD_4)) {
out[6 * s + 2] = 0x1;
out[6 * s + 4] = 0x0;
out[8 * s + 6] = 0x1;
} else if ((__real__ in[s] > QAM256_THRESHOLD_3) || (__real__ in[s] < -QAM256_THRESHOLD_3)) {
out[6 * s + 2] = 0x0;
out[6 * s + 4] = 0x0;
out[8 * s + 6] = 0x1;
} else if ((__real__ in[s] > QAM256_THRESHOLD_2) || (__real__ in[s] < -QAM256_THRESHOLD_2)) {
out[6 * s + 2] = 0x0;
out[6 * s + 4] = 0x1;
out[8 * s + 6] = 0x1;
} else if ((__real__ in[s] > QAM256_THRESHOLD_1) || (__real__ in[s] < -QAM256_THRESHOLD_1)) {
out[6 * s + 2] = 0x0;
out[6 * s + 4] = 0x1;
out[8 * s + 6] = 0x0;
} else {
out[6 * s + 2] = 0x0;
out[6 * s + 4] = 0x0;
out[8 * s + 6] = 0x0;
}
if (__imag__ in[s] > 0) {
out[8 * s + 1] = 0x0;
} else {
out[8 * s + 1] = 0x1;
}
if ((__imag__ in[s] > QAM256_THRESHOLD_7) || (__imag__ in[s] < -QAM256_THRESHOLD_7)) {
out[8 * s + 3] = 0x1;
out[8 * s + 5] = 0x1;
out[8 * s + 7] = 0x1;
} else if ((__imag__ in[s] > QAM256_THRESHOLD_6) || (__imag__ in[s] < -QAM256_THRESHOLD_6)) {
out[6 * s + 3] = 0x1;
out[6 * s + 5] = 0x1;
out[8 * s + 7] = 0x0;
} else if ((__imag__ in[s] > QAM256_THRESHOLD_5) || (__imag__ in[s] < -QAM256_THRESHOLD_5)) {
out[6 * s + 3] = 0x1;
out[6 * s + 5] = 0x0;
out[8 * s + 7] = 0x0;
} else if ((__imag__ in[s] > QAM256_THRESHOLD_4) || (__imag__ in[s] < -QAM256_THRESHOLD_4)) {
out[6 * s + 3] = 0x1;
out[6 * s + 5] = 0x0;
out[8 * s + 7] = 0x1;
} else if ((__imag__ in[s] > QAM256_THRESHOLD_3) || (__imag__ in[s] < -QAM256_THRESHOLD_3)) {
out[6 * s + 3] = 0x0;
out[6 * s + 5] = 0x0;
out[8 * s + 7] = 0x1;
} else if ((__imag__ in[s] > QAM256_THRESHOLD_2) || (__imag__ in[s] < -QAM256_THRESHOLD_2)) {
out[6 * s + 3] = 0x0;
out[6 * s + 5] = 0x1;
out[8 * s + 7] = 0x1;
} else if ((__imag__ in[s] > QAM256_THRESHOLD_1) || (__imag__ in[s] < -QAM256_THRESHOLD_1)) {
out[6 * s + 3] = 0x0;
out[6 * s + 5] = 0x1;
out[8 * s + 7] = 0x0;
} else {
out[6 * s + 3] = 0x0;
out[6 * s + 5] = 0x0;
out[8 * s + 7] = 0x0;
}
}
}

@ -27,6 +27,13 @@
#define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
#define QAM256_THRESHOLD_1 2 / sqrt(170)
#define QAM256_THRESHOLD_2 4 / sqrt(170)
#define QAM256_THRESHOLD_3 6 / sqrt(170)
#define QAM256_THRESHOLD_4 8 / sqrt(170)
#define QAM256_THRESHOLD_5 10 / sqrt(170)
#define QAM256_THRESHOLD_6 12 / sqrt(170)
#define QAM256_THRESHOLD_7 14 / sqrt(170)
void hard_bpsk_demod(const cf_t* in,
uint8_t* out,
@ -43,3 +50,5 @@ void hard_qam16_demod(const cf_t* in,
void hard_qam64_demod(const cf_t* in,
uint8_t* out,
uint32_t N);
void hard_qam256_demod(const cf_t* in, uint8_t* out, uint32_t N);

@ -158,3 +158,25 @@ void set_64QAMtable(cf_t* table)
table[63] = -QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
}
/**
* Set the 256QAM modulation table */
void set_256QAMtable(cf_t* table)
{
// LTE-256QAM constellation:
// see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.5]
for (uint32_t i = 0; i < 256; i++) {
float offset = -1;
float real = 0;
float imag = 0;
for (uint32_t j = 0; j < 4; j++) {
real += offset;
imag += offset;
offset *= 2;
real *= ((i & (1 << (2 * j + 1)))) ? +1 : -1;
imag *= ((i & (1 << (2 * j + 0)))) ? +1 : -1;
}
__real__ table[i] = real / sqrt(170);
__imag__ table[i] = imag / sqrt(170);
}
}

@ -52,3 +52,5 @@ void set_QPSKtable(cf_t* table);
void set_16QAMtable(cf_t* table);
void set_64QAMtable(cf_t* table);
void set_256QAMtable(cf_t* table);

@ -119,6 +119,13 @@ void mod_64qam_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint
}
}
void mod_256qam_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits)
{
for (int i = 0; i < nbits / 8; i++) {
symbols[i] = q->symbol_table[bits[i]];
}
}
/* Assumes packet bits as input */
int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint32_t nbits)
{
@ -144,6 +151,9 @@ int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symb
case 6:
mod_64qam_bytes(q, bits, symbols, nbits);
break;
case 8:
mod_256qam_bytes(q, bits, symbols, nbits);
break;
default:
ERROR("srslte_mod_modulate_bytes() accepts QPSK/16QAM/64QAM modulations only\n");
return -1;

@ -53,6 +53,9 @@ void srslte_modem_table_free(srslte_modem_table_t* q) {
if (q->symbol_table_16qam) {
free(q->symbol_table_16qam);
}
if (q->symbol_table_256qam) {
free(q->symbol_table_256qam);
}
bzero(q, sizeof(srslte_modem_table_t));
}
void srslte_modem_table_reset(srslte_modem_table_t* q) {
@ -108,6 +111,14 @@ int srslte_modem_table_lte(srslte_modem_table_t* q, srslte_mod_t modulation) {
}
set_64QAMtable(q->symbol_table);
break;
case SRSLTE_MOD_256QAM:
q->nbits_x_symbol = 8;
q->nsymbols = 256;
if (table_create(q)) {
return SRSLTE_ERROR;
}
set_256QAMtable(q->symbol_table);
break;
}
return SRSLTE_SUCCESS;
}
@ -147,6 +158,9 @@ void srslte_modem_table_bytes(srslte_modem_table_t* q) {
case 6:
q->byte_tables_init = true;
break;
case 8:
q->byte_tables_init = true;
break;
}
}

@ -29,11 +29,13 @@ add_test(modem_bpsk modem_test -n 1024 -m 1)
add_test(modem_qpsk modem_test -n 1024 -m 2)
add_test(modem_qam16 modem_test -n 1024 -m 4)
add_test(modem_qam64 modem_test -n 1008 -m 6)
add_test(modem_qam256 modem_test -n 1024 -m 8)
add_test(modem_bpsk_soft modem_test -n 1024 -m 1)
add_test(modem_qpsk_soft modem_test -n 1024 -m 2)
add_test(modem_qam16_soft modem_test -n 1024 -m 4)
add_test(modem_qam64_soft modem_test -n 1008 -m 6)
add_test(modem_qam256_soft modem_test -n 1024 -m 8)
add_executable(soft_demod_test soft_demod_test.c)
target_link_libraries(soft_demod_test srslte_phy)

@ -63,6 +63,9 @@ void parse_args(int argc, char **argv) {
case 6:
modulation = SRSLTE_MOD_64QAM;
break;
case 8:
modulation = SRSLTE_MOD_256QAM;
break;
default:
ERROR("Invalid modulation %d. Possible values: "
"(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n",

@ -68,6 +68,9 @@ void parse_args(int argc, char **argv) {
case 6:
modulation = SRSLTE_MOD_64QAM;
break;
case 8:
modulation = SRSLTE_MOD_256QAM;
break;
default:
ERROR("Invalid modulation %d. Possible values: "
"(1: BPSK, 2: QPSK, 4: QAM16, 6: QAM64)\n",
@ -96,6 +99,8 @@ float mse_threshold() {
return 0.11;
case SRSLTE_MOD_64QAM:
return 0.19;
case SRSLTE_MOD_256QAM:
return 0.3;
default:
return -1.0;
}

Loading…
Cancel
Save