PDSCH Video demo working

master
ismagom 10 years ago
parent 40c7db7009
commit 605f102682

@ -34,24 +34,24 @@ FUNCTION(BuildMex)
cmake_parse_arguments(BuildMex "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(BuildMex "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (MATLAB_FOUND) if (MATLAB_FOUND)
add_library(${BuildMex_MEXNAME}-mat SHARED ${BuildMex_SOURCES}) add_library(${BuildMex_MEXNAME}-mat SHARED ${BuildMex_SOURCES})
target_include_directories(${BuildMex_MEXNAME}-mat PUBLIC ${MATLAB_INCLUDE_DIR}) #target_include_directories(${BuildMex_MEXNAME}-mat PUBLIC ${MATLAB_INCLUDE_DIR})
set_target_properties(${BuildMex_MEXNAME}-mat PROPERTIES set_target_properties(${BuildMex_MEXNAME}-mat PROPERTIES
SUFFIX "${MATLAB_MEX_EXTENSION}" SUFFIX "${MATLAB_MEX_EXTENSION}"
PREFIX "liblte_" PREFIX "liblte_"
OUTPUT_NAME "${BuildMex_MEXNAME}" OUTPUT_NAME "${BuildMex_MEXNAME}"
COMPILE_FLAGS "-fvisibility=default ${MATLAB_MEX_CFLAGS}" COMPILE_FLAGS "-fvisibility=default ${MATLAB_MEX_CFLAGS} -I${MATLAB_INCLUDE_DIR}"
) )
target_link_libraries(${BuildMex_MEXNAME}-mat ${BuildMex_LIBRARIES} ${MATLAB_MEX_LIBRARY}) target_link_libraries(${BuildMex_MEXNAME}-mat ${BuildMex_LIBRARIES} ${MATLAB_MEX_LIBRARY})
install(TARGETS ${BuildMex_MEXNAME}-mat DESTINATION "${MEX_DIR}/liblte/") install(TARGETS ${BuildMex_MEXNAME}-mat DESTINATION "${MEX_DIR}/liblte/")
endif(MATLAB_FOUND) endif(MATLAB_FOUND)
if (OCTAVE_FOUND) if (OCTAVE_FOUND)
add_library(${BuildMex_MEXNAME}-oct SHARED ${BuildMex_SOURCES}) add_library(${BuildMex_MEXNAME}-oct SHARED ${BuildMex_SOURCES})
target_include_directories(${BuildMex_MEXNAME}-oct PUBLIC ${OCTAVE_INCLUDE_DIR}) #target_include_directories(${BuildMex_MEXNAME}-oct PUBLIC ${OCTAVE_INCLUDE_DIR})
set_target_properties(${BuildMex_MEXNAME}-oct PROPERTIES set_target_properties(${BuildMex_MEXNAME}-oct PROPERTIES
SUFFIX ".${OCTAVE_MEXFILE_EXT}" SUFFIX ".${OCTAVE_MEXFILE_EXT}"
PREFIX "liblte_" PREFIX "liblte_"
OUTPUT_NAME "${BuildMex_MEXNAME}" OUTPUT_NAME "${BuildMex_MEXNAME}"
COMPILE_FLAGS "-fvisibility=default ${OCTAVE_MEX_CFLAGS} -DUNDEF_BOOL" COMPILE_FLAGS "-fvisibility=default ${OCTAVE_MEX_CFLAGS} -DUNDEF_BOOL -I${OCTAVE_INCLUDE_DIR}"
) )
target_link_libraries(${BuildMex_MEXNAME}-oct ${BuildMex_LIBRARIES} ${OCTAVE_LIBRARIES}) target_link_libraries(${BuildMex_MEXNAME}-oct ${BuildMex_LIBRARIES} ${OCTAVE_LIBRARIES})
install(TARGETS ${BuildMex_MEXNAME}-oct DESTINATION "${MEX_DIR}/liblte/") install(TARGETS ${BuildMex_MEXNAME}-oct DESTINATION "${MEX_DIR}/liblte/")

@ -36,6 +36,8 @@
//#define METADATA_VERBOSE //#define METADATA_VERBOSE
//#define HIDE_MESSAGES
void my_handler(uhd::msg::type_t type, const std::string & msg) void my_handler(uhd::msg::type_t type, const std::string & msg)
{ {
//handle the message... //handle the message...
@ -124,7 +126,9 @@ int cuhd_open(char *args, void **h)
// handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512"); // handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512");
handler->usrp->set_clock_source("internal"); handler->usrp->set_clock_source("internal");
#ifdef HIDE_MESSAGES
uhd::msg::register_handler(my_handler); uhd::msg::register_handler(my_handler);
#endif
std::string otw, cpu; std::string otw, cpu;
otw = "sc16"; otw = "sc16";

@ -60,12 +60,12 @@ lte_cell_t cell = {
int net_port = -1; // -1 generates random data int net_port = -1; // -1 generates random data
uint32_t cfi=1; uint32_t cfi=2;
uint32_t mcs_idx = 1, last_mcs_idx = 1; uint32_t mcs_idx = 1, last_mcs_idx = 1;
int nof_frames = -1; int nof_frames = -1;
char *uhd_args = ""; char *uhd_args = "";
float uhd_amp = 0.1, uhd_gain = 70.0, uhd_freq = 2400000000; float uhd_amp = 0.03, uhd_gain = 70.0, uhd_freq = 2400000000;
bool null_file_sink=false; bool null_file_sink=false;
filesink_t fsink; filesink_t fsink;
@ -303,12 +303,13 @@ reverse(register unsigned int x)
uint32_t prbset_to_bitmask() { uint32_t prbset_to_bitmask() {
uint32_t mask=0; uint32_t mask=0;
for (int i=0;i<cell.nof_prb;i++) { int nb = (int) ceilf((float) cell.nof_prb / ra_type0_P(cell.nof_prb));
for (int i=0;i<nb;i++) {
if (i >= prbset_orig && i < prbset_orig + prbset_num) { if (i >= prbset_orig && i < prbset_orig + prbset_num) {
mask = mask | (0x1<<i); mask = mask | (0x1<<i);
} }
} }
return reverse(mask)>>(32-cell.nof_prb); return reverse(mask)>>(32-nb);
} }
int update_radl() { int update_radl() {
@ -324,10 +325,11 @@ int update_radl() {
ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb); ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb);
ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM); ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM);
ra_mcs_from_idx_dl(mcs_idx, cell.nof_prb, &ra_dl.mcs); ra_mcs_from_idx_dl(mcs_idx, prb_alloc.slot[0].nof_prb, &ra_dl.mcs);
ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
pdsch_harq_reset(&harq_process);
if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) { if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) {
fprintf(stderr, "Error configuring HARQ process\n"); fprintf(stderr, "Error configuring HARQ process\n");
return -1; return -1;
@ -355,7 +357,7 @@ int update_control() {
if(input[0] == 27) { if(input[0] == 27) {
switch(input[2]) { switch(input[2]) {
case RIGHT_KEY: case RIGHT_KEY:
if (prbset_orig + prbset_num < cell.nof_prb) if (prbset_orig + prbset_num < (int) ceilf((float) cell.nof_prb / ra_type0_P(cell.nof_prb)))
prbset_orig++; prbset_orig++;
break; break;
case LEFT_KEY: case LEFT_KEY:
@ -363,7 +365,7 @@ int update_control() {
prbset_orig--; prbset_orig--;
break; break;
case UP_KEY: case UP_KEY:
if (prbset_num < cell.nof_prb) if (prbset_num < (int) ceilf((float) cell.nof_prb / ra_type0_P(cell.nof_prb)))
prbset_num++; prbset_num++;
break; break;
case DOWN_KEY: case DOWN_KEY:
@ -372,6 +374,7 @@ int update_control() {
prbset_num--; prbset_num--;
break; break;
} }
printf("num: %d, orig: %d\n", prbset_num, prbset_orig);
} else { } else {
last_mcs_idx = mcs_idx; last_mcs_idx = mcs_idx;
mcs_idx = atoi(input); mcs_idx = atoi(input);
@ -408,7 +411,7 @@ void *net_thread_fnc(void *arg) {
if (n > 0) { if (n > 0) {
int nbytes = 1+(ra_dl.mcs.tbs-1)/8; int nbytes = 1+(ra_dl.mcs.tbs-1)/8;
rpm += n; rpm += n;
printf("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes); INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes);
wpm = 0; wpm = 0;
while (rpm >= nbytes) { while (rpm >= nbytes) {
// wait for packet to be transmitted // wait for packet to be transmitted
@ -423,7 +426,9 @@ void *net_thread_fnc(void *arg) {
INFO("%d bytes left in buffer for next packet\n", rpm); INFO("%d bytes left in buffer for next packet\n", rpm);
memcpy(data_unpacked, &data_unpacked[wpm], rpm * sizeof(uint8_t)); memcpy(data_unpacked, &data_unpacked[wpm], rpm * sizeof(uint8_t));
} }
} else if (n < 0) { } else if (n == 0) {
rpm = 0;
} else {
fprintf(stderr, "Error receiving from network\n"); fprintf(stderr, "Error receiving from network\n");
exit(-1); exit(-1);
} }
@ -441,7 +446,7 @@ int main(int argc, char **argv) {
cf_t *sf_symbols[MAX_PORTS]; cf_t *sf_symbols[MAX_PORTS];
cf_t *slot1_symbols[MAX_PORTS]; cf_t *slot1_symbols[MAX_PORTS];
dci_msg_t dci_msg; dci_msg_t dci_msg;
dci_location_t locations[NSUBFRAMES_X_FRAME][10]; dci_location_t locations[NSUBFRAMES_X_FRAME][30];
uint32_t sfn; uint32_t sfn;
chest_dl_t est; chest_dl_t est;
@ -462,8 +467,8 @@ int main(int argc, char **argv) {
cell.phich_resources = R_1; cell.phich_resources = R_1;
sfn = 0; sfn = 0;
prbset_num = cell.nof_prb; prbset_num = (int) ceilf((float) cell.nof_prb / ra_type0_P(cell.nof_prb));
last_prbset_num = cell.nof_prb; last_prbset_num = prbset_num;
/* this *must* be called after setting slot_len_* */ /* this *must* be called after setting slot_len_* */
base_init(); base_init();
@ -506,7 +511,8 @@ int main(int argc, char **argv) {
/* Initiate valid DCI locations */ /* Initiate valid DCI locations */
for (i=0;i<NSUBFRAMES_X_FRAME;i++) { for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
pdcch_ue_locations(&pdcch, locations[i], 10, i, cfi, 1234); pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, 1234);
} }
nf = 0; nf = 0;

@ -47,7 +47,7 @@
#include "cuhd_utils.h" #include "cuhd_utils.h"
#endif #endif
#define STDOUT_COMPACT //#define STDOUT_COMPACT
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
#include "liblte/graphics/plot.h" #include "liblte/graphics/plot.h"
@ -215,19 +215,20 @@ ue_dl_t ue_dl;
ue_sync_t ue_sync; ue_sync_t ue_sync;
prog_args_t prog_args; prog_args_t prog_args;
uint32_t sfn = 0; // system frame number
cf_t *sf_buffer;
netsink_t net_sink, net_sink_signal;
int main(int argc, char **argv) { int main(int argc, char **argv) {
int ret; int ret;
cf_t *sf_buffer;
lte_cell_t cell; lte_cell_t cell;
int64_t sf_cnt; int64_t sf_cnt;
ue_mib_t ue_mib; ue_mib_t ue_mib;
void *uhd; void *uhd;
uint32_t nof_trials = 0; uint32_t nof_trials = 0;
uint32_t sfn = 0; // system frame number
int n; int n;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN]; uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
uint32_t sfn_offset; uint32_t sfn_offset;
netsink_t net_sink, net_sink_signal;
parse_args(&prog_args, argc, argv); parse_args(&prog_args, argc, argv);
@ -236,12 +237,14 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port); fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port);
exit(-1); exit(-1);
} }
netsink_set_nonblocking(&net_sink);
} }
if (prog_args.net_port_signal > 0) { if (prog_args.net_port_signal > 0) {
if (netsink_init(&net_sink_signal, prog_args.net_address_signal, prog_args.net_port_signal, NETSINK_UDP)) { if (netsink_init(&net_sink_signal, prog_args.net_address_signal, prog_args.net_port_signal, NETSINK_UDP)) {
fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address_signal, prog_args.net_port_signal); fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address_signal, prog_args.net_port_signal);
exit(-1); exit(-1);
} }
netsink_set_nonblocking(&net_sink_signal);
} }
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
@ -352,13 +355,6 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error calling ue_sync_work()\n"); fprintf(stderr, "Error calling ue_sync_work()\n");
} }
if (prog_args.net_port_signal > 0) {
if (netsink_write(&net_sink_signal, sf_buffer, ue_sync_sf_len(&ue_sync)) < 0) {
fprintf(stderr, "Error sending data through UDP socket\n");
perror("write");
}
}
/* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */ /* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
if (ret == 1) { if (ret == 1) {
switch (state) { switch (state) {
@ -403,7 +399,7 @@ int main(int argc, char **argv) {
if (prog_args.net_port > 0) { if (prog_args.net_port > 0) {
bit_unpack_vector(data_packed, data, n); bit_unpack_vector(data_packed, data, n);
if (netsink_write(&net_sink, data, 1+(n-1)/8) < 0) { if (netsink_write(&net_sink, data, 1+(n-1)/8) < 0) {
fprintf(stderr, "Error sending data through UDP socket\n"); fprintf(stderr, "Error sending data through socket\n");
} }
} }
} }
@ -411,31 +407,38 @@ int main(int argc, char **argv) {
rsrq = VEC_EMA(chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.05); rsrq = VEC_EMA(chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.05);
rsrp = VEC_EMA(chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05); rsrp = VEC_EMA(chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05);
snr = VEC_EMA(chest_dl_get_snr(&ue_dl.chest), snr, 0.05); snr = VEC_EMA(chest_dl_get_snr(&ue_dl.chest), snr, 0.01);
nframes++; nframes++;
if (isnan(rsrq)) { if (isnan(rsrq)) {
rsrq = 0; rsrq = 0;
} }
if (isnan(snr)) {
snr = 0;
}
if (isnan(rsrp)) {
rsrp = 0;
}
} }
if (ue_sync_get_sfidx(&ue_sync) != 5 && ue_sync_get_sfidx(&ue_sync) != 0) { if (ue_sync_get_sfidx(&ue_sync) != 5 && ue_sync_get_sfidx(&ue_sync) != 0) {
pdcch_tx++; pdcch_tx++;
} }
// Plot and Printf // Plot and Printf
if (ue_sync_get_sfidx(&ue_sync) == 5) { if (ue_sync_get_sfidx(&ue_sync) == 5) {
#ifdef STDOUT_COMPACT #ifdef STDOUT_COMPACT
printf("SFN: %4d, PDCCH-Miss: %5.2f%% (%d), PDSCH-BLER: %5.2f%% (%d blocks)\r", printf("SFN: %4d, PDCCH-Miss: %5.2f%% (%d missed), PDSCH-BLER: %5.2f%% (%d errors)\r",
sfn, 100*(1-(float) ue_dl.nof_pdcch_detected/nof_trials),ue_dl.nof_pdcch_detected-pdcch_tx, sfn, 100*(1-(float) ue_dl.nof_pdcch_detected/nof_trials),pdcch_tx-ue_dl.nof_pdcch_detected,
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total,nof_trials, ue_dl.pkts_total); (float) 100*ue_dl.pkt_errors/ue_dl.pkts_total,ue_dl.pkt_errors);
#else #else
printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, " printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, "
"RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %4.1f dB, " "RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %4.1f dB, "
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%% (%d blocks)\r", "PDCCH-Miss: %5.2f%% (%d missed), PDSCH-BLER: %5.2f%% (%d errors)\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000, ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rsrp*1000)-gain_offset, 10*log10(rsrp*1000)-gain_offset,
10*log10(rsrq), 10*log10(snr), 10*log10(rsrq), 10*log10(snr),
100*(1-(float) ue_dl.nof_pdcch_detected/nof_trials), 100*(1-(float) ue_dl.nof_pdcch_detected/nof_trials), pdcch_tx-ue_dl.nof_pdcch_detected,
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total,nof_trials, ue_dl.pkts_total); (float) 100*ue_dl.pkt_errors/ue_dl.pkts_total, ue_dl.pkt_errors);
#endif #endif
} }
@ -447,6 +450,7 @@ int main(int argc, char **argv) {
sfn = 0; sfn = 0;
} }
} }
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) { if (!prog_args.disable_plots) {
plot_sf_idx = ue_sync_get_sfidx(&ue_sync); plot_sf_idx = ue_sync_get_sfidx(&ue_sync);
@ -488,7 +492,7 @@ int main(int argc, char **argv) {
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
plot_waterfall_t poutfft; //plot_waterfall_t poutfft;
plot_real_t p_sync, pce; plot_real_t p_sync, pce;
plot_scatter_t pscatequal, pscatequal_pdcch; plot_scatter_t pscatequal, pscatequal_pdcch;
@ -516,9 +520,9 @@ void *plot_thread_run(void *arg) {
tmp_plot2[i] = -80; tmp_plot2[i] = -80;
} }
} }
for (i=0;i<CP_NSYMB(ue_dl.cell.cp);i++) { //for (i=0;i<CP_NSYMB(ue_dl.cell.cp);i++) {
plot_waterfall_appendNewData(&poutfft, &tmp_plot[i*RE_X_RB*ue_dl.cell.nof_prb], RE_X_RB*ue_dl.cell.nof_prb); // plot_waterfall_appendNewData(&poutfft, &tmp_plot[i*RE_X_RB*ue_dl.cell.nof_prb], RE_X_RB*ue_dl.cell.nof_prb);
} //}
plot_real_setNewData(&pce, tmp_plot2, REFSIGNAL_NUM_SF(ue_dl.cell.nof_prb,0)); plot_real_setNewData(&pce, tmp_plot2, REFSIGNAL_NUM_SF(ue_dl.cell.nof_prb,0));
if (!prog_args.input_file_name) { if (!prog_args.input_file_name) {
int max = vec_max_fi(ue_sync.strack.pss.conv_output_avg, ue_sync.strack.pss.frame_size+ue_sync.strack.pss.fft_size-1); int max = vec_max_fi(ue_sync.strack.pss.conv_output_avg, ue_sync.strack.pss.frame_size+ue_sync.strack.pss.fft_size-1);
@ -533,6 +537,17 @@ void *plot_thread_run(void *arg) {
plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.pdsch_d, nof_symbols); plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.pdsch_d, nof_symbols);
plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.pdcch_d, 36*ue_dl.pdcch.nof_cce); plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.pdcch_d, 36*ue_dl.pdcch.nof_cce);
if (plot_sf_idx == 1) {
if (prog_args.net_port_signal > 0) {
if (netsink_write(&net_sink_signal, &sf_buffer[ue_sync_sf_len(&ue_sync)/7],
ue_sync_sf_len(&ue_sync)) < 0)
{
fprintf(stderr, "Error sending data through UDP socket\n");
perror("write");
}
}
}
} }
return NULL; return NULL;
@ -542,9 +557,9 @@ void init_plots() {
plot_init(); plot_init();
plot_waterfall_init(&poutfft, RE_X_RB * ue_dl.cell.nof_prb, 1000); //plot_waterfall_init(&poutfft, RE_X_RB * ue_dl.cell.nof_prb, 1000);
plot_waterfall_setTitle(&poutfft, "Output FFT - Magnitude"); //plot_waterfall_setTitle(&poutfft, "Output FFT - Magnitude");
plot_waterfall_setPlotYAxisScale(&poutfft, -40, 40); //plot_waterfall_setPlotYAxisScale(&poutfft, -40, 40);
plot_real_init(&pce); plot_real_init(&pce);
plot_real_setTitle(&pce, "Channel Response - Magnitude"); plot_real_setTitle(&pce, "Channel Response - Magnitude");

@ -34,17 +34,20 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include "liblte/config.h" #include "liblte/config.h"
typedef enum {NETSINK_UDP, NETSINK_TCP} netsink_type_t;
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int sockfd; int sockfd;
bool connected;
netsink_type_t type;
struct sockaddr_in servaddr; struct sockaddr_in servaddr;
}netsink_t; }netsink_t;
typedef enum {NETSINK_UDP, NETSINK_TCP} netsink_type_t;
LIBLTE_API int netsink_init(netsink_t *q, LIBLTE_API int netsink_init(netsink_t *q,
char *address, char *address,
int port, int port,
@ -56,6 +59,8 @@ LIBLTE_API int netsink_write(netsink_t *q,
void *buffer, void *buffer,
int nof_bytes); int nof_bytes);
LIBLTE_API int netsink_set_nonblocking(netsink_t *q);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {

@ -43,7 +43,7 @@
#include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/dci.h"
#include "liblte/phy/phch/regs.h" #include "liblte/phy/phch/regs.h"
#define TDEC_MAX_ITERATIONS 6 #define TDEC_MAX_ITERATIONS 5
typedef _Complex float cf_t; typedef _Complex float cf_t;

@ -43,7 +43,7 @@ typedef _Complex float cf_t;
#define VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n)+1)) #define VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n)+1))
// Exponential moving average // Exponential moving average
#define VEC_EMA(data, average, alpha) (average)==0?(data):((alpha)*(data)+(1-alpha)*(average)) #define VEC_EMA(data, average, alpha) ((alpha)*(data)+(1-alpha)*(average))
/** Return the sum of all the elements */ /** Return the sum of all the elements */
LIBLTE_API int vec_acc_ii(int *x, uint32_t len); LIBLTE_API int vec_acc_ii(int *x, uint32_t len);

@ -43,6 +43,8 @@
#define CHEST_RS_AVERAGE_TIME 2 #define CHEST_RS_AVERAGE_TIME 2
#define CHEST_RS_AVERAGE_FREQ 3 #define CHEST_RS_AVERAGE_FREQ 3
#define NOISE_POWER_USE_ESTIMATES
/** 3GPP LTE Downlink channel estimator and equalizer. /** 3GPP LTE Downlink channel estimator and equalizer.
* Estimates the channel in the resource elements transmitting references and interpolates for the rest * Estimates the channel in the resource elements transmitting references and interpolates for the rest
@ -115,15 +117,14 @@ int chest_dl_init(chest_dl_t *q, lte_cell_t cell)
} }
/* Set default time/freq filters */ /* Set default time/freq filters */
float f[3]={0.1, 0.8, 0.1}; //float f[3]={0.1, 0.8, 0.1};
chest_dl_set_filter_freq(q, f, 3); //chest_dl_set_filter_freq(q, f, 3);
//float f[5]={0.05, 0.15, 0.6, 0.15, 0.05}; float f[5]={0.05, 0.15, 0.6, 0.15, 0.05};
//chest_dl_set_filter_freq(q, f, 5); chest_dl_set_filter_freq(q, f, 5);
//float t[2]={0.1, 0.9}; float t[2]={0.15, 0.85};
float t[1] = {1.0}; chest_dl_set_filter_time(q, t, 2);
chest_dl_set_filter_time(q, t, 1);
q->cell = cell; q->cell = cell;
} }
@ -194,6 +195,10 @@ int chest_dl_set_filter_time(chest_dl_t *q, float *filter, uint32_t filter_len)
} }
#ifdef NOISE_POWER_USE_ESTIMATES
/* Uses the difference between the averaged and non-averaged pilot estimates */
static float estimate_noise_port(chest_dl_t *q, uint32_t port_id, cf_t *avg_pilots) { static float estimate_noise_port(chest_dl_t *q, uint32_t port_id, cf_t *avg_pilots) {
/* Use difference between averaged and noisy LS pilot estimates */ /* Use difference between averaged and noisy LS pilot estimates */
vec_sub_ccc(avg_pilots, q->pilot_estimates[port_id], vec_sub_ccc(avg_pilots, q->pilot_estimates[port_id],
@ -202,6 +207,22 @@ static float estimate_noise_port(chest_dl_t *q, uint32_t port_id, cf_t *avg_pilo
return vec_avg_power_cf(q->tmp_noise, REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); return vec_avg_power_cf(q->tmp_noise, REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
} }
#else
/* Uses the 5 empty transmitted SC before and after the SSS and PSS sequences for noise estimation */
static float estimate_noise_empty_sc(chest_dl_t *q, cf_t *input) {
int k_sss = (CP_NSYMB(q->cell.cp) - 2) * q->cell.nof_prb * RE_X_RB + q->cell.nof_prb * RE_X_RB / 2 - 31;
float noise_power = 0;
noise_power += vec_avg_power_cf(&input[k_sss-5], 5); // 5 empty SC before SSS
noise_power += vec_avg_power_cf(&input[k_sss+62], 5); // 5 empty SC after SSS
int k_pss = (CP_NSYMB(q->cell.cp) - 1) * q->cell.nof_prb * RE_X_RB + q->cell.nof_prb * RE_X_RB / 2 - 31;
noise_power += vec_avg_power_cf(&input[k_pss-5], 5); // 5 empty SC before PSS
noise_power += vec_avg_power_cf(&input[k_pss+62], 5); // 5 empty SC after PSS
return noise_power;
}
#endif
#define pilot_est(idx) q->pilot_estimates[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)] #define pilot_est(idx) q->pilot_estimates[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
#define pilot_avg(idx) q->pilot_estimates_average[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)] #define pilot_avg(idx) q->pilot_estimates_average[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
#define pilot_tmp(idx) q->tmp_freqavg[REFSIGNAL_PILOT_IDX(idx,l,q->cell)] #define pilot_tmp(idx) q->tmp_freqavg[REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
@ -227,11 +248,6 @@ static void average_pilots(chest_dl_t *q, uint32_t port_id)
} }
} }
/* Compute noise estimation before time averaging.
* FIXME: Apparently the noise estimation performance is better with frequency averaging only
*/
q->noise_estimate[port_id] = estimate_noise_port(q, port_id, q->tmp_freqavg);
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) { for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
/* Filter in time domain. */ /* Filter in time domain. */
if (q->filter_time_len > 0) { if (q->filter_time_len > 0) {
@ -252,6 +268,10 @@ static void average_pilots(chest_dl_t *q, uint32_t port_id)
memcpy(&pilot_avg(0), &pilot_tmp(0), nref * sizeof(cf_t)); memcpy(&pilot_avg(0), &pilot_tmp(0), nref * sizeof(cf_t));
} }
} }
#ifdef NOISE_POWER_USE_ESTIMATES
q->noise_estimate[port_id] = estimate_noise_port(q, port_id, q->pilot_estimates_average[port_id]);
#endif
} }
#define cesymb(i) ce[RE_IDX(q->cell.nof_prb,i,0)] #define cesymb(i) ce[RE_IDX(q->cell.nof_prb,i,0)]
@ -308,6 +328,8 @@ float chest_dl_rssi(chest_dl_t *q, cf_t *input, uint32_t port_id) {
return rssi/nsymbols; return rssi/nsymbols;
} }
//#define RSRP_FROM_ESTIMATES
float chest_dl_rsrp(chest_dl_t *q, uint32_t port_id) { float chest_dl_rsrp(chest_dl_t *q, uint32_t port_id) {
#ifdef RSRP_FROM_ESTIMATES #ifdef RSRP_FROM_ESTIMATES
return vec_avg_power_cf(q->pilot_estimates[port_id], return vec_avg_power_cf(q->pilot_estimates[port_id],
@ -342,6 +364,9 @@ int chest_dl_estimate_port(chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx
interpolate_pilots(q, ce, port_id); interpolate_pilots(q, ce, port_id);
} }
#ifndef NOISE_POWER_USE_ESTIMATES
q->noise_estimate[port_id] = estimate_noise_empty_sc(q, input);
#endif
return 0; return 0;
} }
@ -361,7 +386,11 @@ float chest_dl_get_noise_estimate(chest_dl_t *q) {
float chest_dl_get_snr(chest_dl_t *q) { float chest_dl_get_snr(chest_dl_t *q) {
// Uses RSRP as an estimation of the useful signal power // Uses RSRP as an estimation of the useful signal power
return chest_dl_get_rsrp(q)/chest_dl_get_noise_estimate(q); #ifdef NOISE_POWER_USE_ESTIMATES
return chest_dl_get_rsrp(q)/chest_dl_get_noise_estimate(q)/sqrt(2*lte_symbol_sz(q->cell.nof_prb));
#else
return chest_dl_get_rsrp(q)/chest_dl_get_noise_estimate(q)/sqrt(2);
#endif
} }
float chest_dl_get_rssi(chest_dl_t *q) { float chest_dl_get_rssi(chest_dl_t *q) {

@ -244,7 +244,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
if (nlhs >= 4) { if (nlhs >= 4) {
plhs[3] = mxCreateDoubleScalar(chest_dl_get_snr(&chest)); plhs[3] = mxCreateDoubleScalar(chest_dl_get_noise_estimate(&chest));
} }
return; return;

@ -33,6 +33,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <strings.h> #include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include "liblte/phy/io/netsink.h" #include "liblte/phy/io/netsink.h"
@ -41,7 +43,6 @@ int netsink_init(netsink_t *q, char *address, int port, netsink_type_t type) {
bzero(q, sizeof(netsink_t)); bzero(q, sizeof(netsink_t));
q->sockfd=socket(AF_INET, type==NETSINK_TCP?SOCK_STREAM:SOCK_DGRAM,0); q->sockfd=socket(AF_INET, type==NETSINK_TCP?SOCK_STREAM:SOCK_DGRAM,0);
if (q->sockfd < 0) { if (q->sockfd < 0) {
perror("socket"); perror("socket");
return -1; return -1;
@ -50,12 +51,8 @@ int netsink_init(netsink_t *q, char *address, int port, netsink_type_t type) {
q->servaddr.sin_family = AF_INET; q->servaddr.sin_family = AF_INET;
q->servaddr.sin_addr.s_addr=inet_addr(address); q->servaddr.sin_addr.s_addr=inet_addr(address);
q->servaddr.sin_port=htons(port); q->servaddr.sin_port=htons(port);
q->connected = false;
printf("Connecting to %s:%d\n", address, port); q->type = type;
if (connect(q->sockfd,&q->servaddr,sizeof(q->servaddr)) < 0) {
perror("connect");
return -1;
}
return 0; return 0;
} }
@ -67,8 +64,45 @@ void netsink_free(netsink_t *q) {
bzero(q, sizeof(netsink_t)); bzero(q, sizeof(netsink_t));
} }
int netsink_set_nonblocking(netsink_t *q) {
if (fcntl(q->sockfd, F_SETFL, O_NONBLOCK)) {
perror("fcntl");
return -1;
}
return 0;
}
int netsink_write(netsink_t *q, void *buffer, int nof_bytes) { int netsink_write(netsink_t *q, void *buffer, int nof_bytes) {
return write(q->sockfd, buffer, nof_bytes); if (!q->connected) {
if (connect(q->sockfd,&q->servaddr,sizeof(q->servaddr)) < 0) {
if (errno == ECONNREFUSED || errno == EINPROGRESS) {
return 0;
} else {
perror("connect");
exit(-1);
return -1;
}
} else {
q->connected = true;
}
}
int n = 0;
if (q->connected) {
n = write(q->sockfd, buffer, nof_bytes);
if (n < 0) {
if (errno == ECONNRESET) {
close(q->sockfd);
q->sockfd=socket(AF_INET, q->type==NETSINK_TCP?SOCK_STREAM:SOCK_DGRAM,0);
if (q->sockfd < 0) {
perror("socket");
return -1;
}
q->connected = false;
return 0;
}
}
}
return n;
} }

@ -93,15 +93,14 @@ int netsource_read(netsource_t *q, void *buffer, int nbytes) {
} }
} }
int n = read(q->connfd, buffer, nbytes); int n = read(q->connfd, buffer, nbytes);
if (n == -1) { if (n == 0) {
if (errno == ECONNRESET) {
printf("Connection closed\n"); printf("Connection closed\n");
close(q->connfd); close(q->connfd);
q->connfd = 0; q->connfd = 0;
return 0; return 0;
} else {
perror("read");
} }
if (n == -1) {
perror("read");
} }
return n; return n;
} }

@ -435,7 +435,6 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float n
static void crc_set_mask_rnti(uint8_t *crc, uint16_t rnti) { static void crc_set_mask_rnti(uint8_t *crc, uint16_t rnti) {
uint32_t i; uint32_t i;
uint8_t mask[16]; uint8_t mask[16];

@ -217,6 +217,10 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
nof_locations = pdcch_ue_locations(&q->pdcch, locations, MAX_CANDIDATES, sf_idx, cfi, q->current_rnti); nof_locations = pdcch_ue_locations(&q->pdcch, locations, MAX_CANDIDATES, sf_idx, cfi, q->current_rnti);
formats = ue_formats; formats = ue_formats;
nof_formats = nof_ue_formats; nof_formats = nof_ue_formats;
if (q->current_rnti == 1234) {
nof_locations = 1;
nof_formats = 1;
}
} }
/* Extract all PDCCH symbols and get LLRs */ /* Extract all PDCCH symbols and get LLRs */

@ -259,6 +259,7 @@ static int find_peak_ok(ue_sync_t *q) {
q->frame_no_cnt = 0; q->frame_no_cnt = 0;
q->frame_total_cnt = 0; q->frame_total_cnt = 0;
q->frame_find_cnt = 0; q->frame_find_cnt = 0;
q->mean_time_offset = 0;
/* Set tracking CFO average to find CFO */ /* Set tracking CFO average to find CFO */
q->strack.mean_cfo = q->sfind.mean_cfo; q->strack.mean_cfo = q->sfind.mean_cfo;
@ -289,10 +290,13 @@ static int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
INFO("Time offset adjustment: %d samples\n", q->time_offset); INFO("Time offset adjustment: %d samples\n", q->time_offset);
} }
/* compute cumulative moving average time offset */
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt);
/* If the PSS peak is beyond the frame (we sample too slowly), /* If the PSS peak is beyond the frame (we sample too slowly),
discard the offseted samples to align next frame */ discard the offseted samples to align next frame */
if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) {
INFO("Positive time offset %d samples. Adjusting now.\n", q->time_offset); INFO("\nPositive time offset %d samples. Mean time offset %f.\n", q->time_offset, q->mean_time_offset);
if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset) < 0) { if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset) < 0) {
fprintf(stderr, "Error receiving from USRP\n"); fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
@ -300,9 +304,6 @@ static int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
q->time_offset = 0; q->time_offset = 0;
} }
/* compute cumulative moving average time offset */
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt);
q->peak_idx = q->sf_len/2 + q->time_offset; q->peak_idx = q->sf_len/2 + q->time_offset;
q->frame_ok_cnt++; q->frame_ok_cnt++;
q->frame_no_cnt = 0; q->frame_no_cnt = 0;
@ -335,7 +336,6 @@ static int receive_samples(ue_sync_t *q) {
q->time_offset = -q->time_offset; q->time_offset = -q->time_offset;
} }
INFO("Receiving %d samples\n", q->frame_len - q->time_offset);
/* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */ /* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */
if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], q->frame_len - q->time_offset) < 0) { if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], q->frame_len - q->time_offset) < 0) {
return LIBLTE_ERROR; return LIBLTE_ERROR;
@ -450,6 +450,7 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
q->input_buffer, q->input_buffer,
q->input_buffer, q->input_buffer,
-sync_get_cfo(&q->strack) / q->fft_size); -sync_get_cfo(&q->strack) / q->fft_size);
} }
*sf_symbols = q->input_buffer; *sf_symbols = q->input_buffer;

@ -14,7 +14,7 @@ postEVM_liblte = zeros(length(SNR_values_db),Nrealizations);
enb.NDLRB = 6; % Number of resource blocks enb.NDLRB = 6; % Number of resource blocks
enb.CellRefP = 2; % One transmit antenna port enb.CellRefP = 1; % One transmit antenna port
enb.NCellID = 0; % Cell ID enb.NCellID = 0; % Cell ID
enb.CyclicPrefix = 'Normal'; % Normal cyclic prefix enb.CyclicPrefix = 'Normal'; % Normal cyclic prefix
enb.DuplexMode = 'FDD'; % FDD enb.DuplexMode = 'FDD'; % FDD
@ -101,6 +101,8 @@ for sf = 0:10
end end
txGrid([1:5 68:72],6:7) = zeros(10,2);
%% OFDM Modulation %% OFDM Modulation
[txWaveform,info] = lteOFDMModulate(enb,txGrid); [txWaveform,info] = lteOFDMModulate(enb,txGrid);
@ -118,7 +120,7 @@ SNR = 10^(SNRdB/20); % Linear SNR
cfg.SamplingRate = info.SamplingRate; cfg.SamplingRate = info.SamplingRate;
% Pass data through the fading channel model % Pass data through the fading channel model
rxWaveform = lteFadingChannel(cfg,txWaveform); %rxWaveform = lteFadingChannel(cfg,txWaveform);
rxWaveform = txWaveform; rxWaveform = txWaveform;
%% Additive Noise %% Additive Noise
@ -149,14 +151,19 @@ addpath('../../debug/lte/phy/lib/ch_estimation/test')
[estChannel, noiseEst(snr_idx)] = lteDLChannelEstimate(enb,cec,rxGrid); [estChannel, noiseEst(snr_idx)] = lteDLChannelEstimate(enb,cec,rxGrid);
output=[]; output=[];
snrest = zeros(10,1); snrest = zeros(10,1);
for i=0:9
nulls = rxGrid([1:5 68:72],6:7);
noiseEst(snr_idx) = var(nulls(:));
%for i=0:9
i=0;
% if (SNR_values_db(snr_idx) < 25) % if (SNR_values_db(snr_idx) < 25)
[d, a, out, snrest(i+1)] = liblte_chest(enb.NCellID,enb.CellRefP,rxGrid(:,i*14+1:(i+1)*14),[0.15 0.7 0.15],[],i); [d, a, out, snrest(i+1)] = liblte_chest(enb.NCellID,enb.CellRefP,rxGrid(:,i*14+1:(i+1)*14),[0.1 0.8 0.1],[0.1 0.9],i);
% else % else
% [d, a, out, snrest(i+1)] = liblte_chest(enb.NCellID,enb.CellRefP,rxGrid(:,i*14+1:(i+1)*14),[0.05 0.9 0.05],[],i); % [d, a, out, snrest(i+1)] = liblte_chest(enb.NCellID,enb.CellRefP,rxGrid(:,i*14+1:(i+1)*14),[0.05 0.9 0.05],[],i);
% end % end
output = [output out]; output = [output out];
end %end
SNRest(snr_idx)=mean(snrest); SNRest(snr_idx)=mean(snrest);
disp(10*log10(SNRest(snr_idx))) disp(10*log10(SNRest(snr_idx)))
%% MMSE Equalization %% MMSE Equalization
@ -196,8 +203,8 @@ end
% %
% subplot(1,2,2) % subplot(1,2,2)
%SNR_liblte = 1./(SNRest*sqrt(2.0*enb.CellRefP*double(info.Nfft))); %SNR_liblte = 1./(SNRest*sqrt(2.0*enb.CellRefP*double(info.Nfft)));
SNR_liblte = SNRest; SNR_liblte = 1./(SNRest*sqrt(2.0));
SNR_matlab = 1./(noiseEst*sqrt(2.0*enb.CellRefP*double(info.Nfft))); SNR_matlab = 1./(noiseEst*sqrt(2.0));
plot(SNR_values_db, SNR_values_db, SNR_values_db, 10*log10(SNR_liblte),SNR_values_db, 10*log10(SNR_matlab)) plot(SNR_values_db, SNR_values_db, SNR_values_db, 10*log10(SNR_liblte),SNR_values_db, 10*log10(SNR_matlab))
%plot(SNR_values_db, 10*log10(noiseTx), SNR_values_db, 10*log10(SNRest),SNR_values_db, 10*log10(noiseEst)) %plot(SNR_values_db, 10*log10(noiseTx), SNR_values_db, 10*log10(SNRest),SNR_values_db, 10*log10(noiseEst))

@ -50,10 +50,10 @@ IF (MATLAB_FOUND OR OCTAVE_FOUND)
INSTALL(TARGETS liblte_mex DESTINATION ${LIBRARY_DIR}) INSTALL(TARGETS liblte_mex DESTINATION ${LIBRARY_DIR})
LIBLTE_SET_PIC(liblte_mex) LIBLTE_SET_PIC(liblte_mex)
if (MATLAB_FOUND) if (MATLAB_FOUND)
target_include_directories(liblte_mex PUBLIC ${MATLAB_INCLUDE_DIR}) include_directories(${MATLAB_INCLUDE_DIR})
endif(MATLAB_FOUND) endif(MATLAB_FOUND)
if (OCTAVE_FOUND) if (OCTAVE_FOUND)
target_include_directories(liblte_mex PUBLIC ${OCTAVE_INCLUDE_DIR}) include_directories(${OCTAVE_INCLUDE_DIR})
endif (OCTAVE_FOUND) endif (OCTAVE_FOUND)
ELSEIF (MATLAB_FOUND OR OCTAVE_FOUND) ELSEIF (MATLAB_FOUND OR OCTAVE_FOUND)

Loading…
Cancel
Save