Initial 256QAM Modem and Demodulator

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

@ -239,10 +239,11 @@ typedef enum SRSLTE_API {
typedef enum SRSLTE_API { SRSLTE_MIMO_DECODER_ZF, SRSLTE_MIMO_DECODER_MMSE } srslte_mimo_decoder_t; typedef enum SRSLTE_API { SRSLTE_MIMO_DECODER_ZF, SRSLTE_MIMO_DECODER_MMSE } srslte_mimo_decoder_t;
typedef enum SRSLTE_API { typedef enum SRSLTE_API {
SRSLTE_MOD_BPSK = 0, SRSLTE_MOD_BPSK = 0,
SRSLTE_MOD_QPSK, SRSLTE_MOD_QPSK,
SRSLTE_MOD_16QAM, SRSLTE_MOD_16QAM,
SRSLTE_MOD_64QAM, SRSLTE_MOD_64QAM,
SRSLTE_MOD_256QAM,
} srslte_mod_t; } srslte_mod_t;
typedef enum { typedef enum {

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

@ -208,6 +208,8 @@ srslte_mod_t srslte_str2mod (char * mod_str) {
return SRSLTE_MOD_16QAM; return SRSLTE_MOD_16QAM;
} else if (!strcmp(mod_str, "64QAM")) { } else if (!strcmp(mod_str, "64QAM")) {
return SRSLTE_MOD_64QAM; return SRSLTE_MOD_64QAM;
} else if (!strcmp(mod_str, "256QAM")) {
return SRSLTE_MOD_256QAM;
} else { } else {
return (srslte_mod_t) SRSLTE_ERROR_INVALID_INPUTS; return (srslte_mod_t) SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -224,6 +226,8 @@ char *srslte_mod_string(srslte_mod_t mod) {
return "16QAM"; return "16QAM";
case SRSLTE_MOD_64QAM: case SRSLTE_MOD_64QAM:
return "64QAM"; return "64QAM";
case SRSLTE_MOD_256QAM:
return "256QAM";
default: default:
return "N/A"; return "N/A";
} }
@ -239,6 +243,8 @@ uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod) {
return 4; return 4;
case SRSLTE_MOD_64QAM: case SRSLTE_MOD_64QAM:
return 6; return 6;
case SRSLTE_MOD_256QAM:
return 8;
default: default:
return 0; 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); hard_qam64_demod(symbols,bits,nsymbols);
nbits=nsymbols*6; nbits=nsymbols*6;
break; break;
case SRSLTE_MOD_256QAM:
hard_qam256_demod(symbols, bits, nsymbols);
nbits = nsymbols * 8;
break;
} }
return nbits; 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_QPSK 100
#define SCALE_SHORT_CONV_QAM16 400 #define SCALE_SHORT_CONV_QAM16 400
#define SCALE_SHORT_CONV_QAM64 700 #define SCALE_SHORT_CONV_QAM64 700
#define SCALE_SHORT_CONV_QAM256 1000
#define SCALE_BYTE_CONV_QPSK 20 #define SCALE_BYTE_CONV_QPSK 20
#define SCALE_BYTE_CONV_QAM16 30 #define SCALE_BYTE_CONV_QAM16 30
#define SCALE_BYTE_CONV_QAM64 40 #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) { void demod_bpsk_lte_b(const cf_t *symbols, int8_t *llr, int nsymbols) {
for (int i=0;i<nsymbols;i++) { 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 #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) { int srslte_demod_soft_demodulate(srslte_mod_t modulation, const cf_t* symbols, float* llr, int nsymbols) {
switch(modulation) { switch(modulation) {
case SRSLTE_MOD_BPSK: 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: case SRSLTE_MOD_64QAM:
demod_64qam_lte(symbols, llr, nsymbols); demod_64qam_lte(symbols, llr, nsymbols);
break; break;
case SRSLTE_MOD_256QAM:
demod_256qam_lte(symbols, llr, nsymbols);
break;
default: default:
ERROR("Invalid modulation %d\n", modulation); ERROR("Invalid modulation %d\n", modulation);
return -1; return -1;
@ -443,6 +499,9 @@ int srslte_demod_soft_demodulate_s(srslte_mod_t modulation, const cf_t* symbols,
case SRSLTE_MOD_64QAM: case SRSLTE_MOD_64QAM:
demod_64qam_lte_s(symbols, llr, nsymbols); demod_64qam_lte_s(symbols, llr, nsymbols);
break; break;
case SRSLTE_MOD_256QAM:
demod_256qam_lte_s(symbols, llr, nsymbols);
break;
default: default:
ERROR("Invalid modulation %d\n", modulation); ERROR("Invalid modulation %d\n", modulation);
return -1; return -1;
@ -464,6 +523,9 @@ int srslte_demod_soft_demodulate_b(srslte_mod_t modulation, const cf_t* symbols,
case SRSLTE_MOD_64QAM: case SRSLTE_MOD_64QAM:
demod_64qam_lte_b(symbols, llr, nsymbols); demod_64qam_lte_b(symbols, llr, nsymbols);
break; break;
case SRSLTE_MOD_256QAM:
demod_256qam_lte_b(symbols, llr, nsymbols);
break;
default: default:
ERROR("Invalid modulation %d\n", modulation); ERROR("Invalid modulation %d\n", modulation);
return -1; 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_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42) #define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/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, void hard_bpsk_demod(const cf_t* in,
uint8_t* out, uint8_t* out,
@ -43,3 +50,5 @@ void hard_qam16_demod(const cf_t* in,
void hard_qam64_demod(const cf_t* in, void hard_qam64_demod(const cf_t* in,
uint8_t* out, uint8_t* out,
uint32_t N); 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; 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_16QAMtable(cf_t* table);
void set_64QAMtable(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 */ /* Assumes packet bits as input */
int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint32_t nbits) int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint32_t nbits)
{ {
@ -143,7 +150,10 @@ int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symb
break; break;
case 6: case 6:
mod_64qam_bytes(q, bits, symbols, nbits); mod_64qam_bytes(q, bits, symbols, nbits);
break; break;
case 8:
mod_256qam_bytes(q, bits, symbols, nbits);
break;
default: default:
ERROR("srslte_mod_modulate_bytes() accepts QPSK/16QAM/64QAM modulations only\n"); ERROR("srslte_mod_modulate_bytes() accepts QPSK/16QAM/64QAM modulations only\n");
return -1; return -1;

@ -53,6 +53,9 @@ void srslte_modem_table_free(srslte_modem_table_t* q) {
if (q->symbol_table_16qam) { if (q->symbol_table_16qam) {
free(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)); bzero(q, sizeof(srslte_modem_table_t));
} }
void srslte_modem_table_reset(srslte_modem_table_t* q) { 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); set_64QAMtable(q->symbol_table);
break; 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; return SRSLTE_SUCCESS;
} }
@ -147,6 +158,9 @@ void srslte_modem_table_bytes(srslte_modem_table_t* q) {
case 6: case 6:
q->byte_tables_init = true; q->byte_tables_init = true;
break; 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_qpsk modem_test -n 1024 -m 2)
add_test(modem_qam16 modem_test -n 1024 -m 4) add_test(modem_qam16 modem_test -n 1024 -m 4)
add_test(modem_qam64 modem_test -n 1008 -m 6) 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_bpsk_soft modem_test -n 1024 -m 1)
add_test(modem_qpsk_soft modem_test -n 1024 -m 2) 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_qam16_soft modem_test -n 1024 -m 4)
add_test(modem_qam64_soft modem_test -n 1008 -m 6) 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) add_executable(soft_demod_test soft_demod_test.c)
target_link_libraries(soft_demod_test srslte_phy) target_link_libraries(soft_demod_test srslte_phy)

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

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

Loading…
Cancel
Save