Merge branch '2rx' into next

This commit is contained in:
Ismael Gomez 2017-03-08 13:38:11 +01:00
commit 58b5791827
43 changed files with 1554 additions and 500 deletions

84
matlab/tests/mimo_test.m Normal file
View File

@ -0,0 +1,84 @@
clear
addpath('../../debug/srslte/lib/mimo/test')
Nt=1;
Nr=1;
Nl=1;
Ncw=1;
txscheme='Port0';
codebook=0;
enb.NDLRB=6;
Ns=enb.NDLRB*12*14;
enb.CyclicPrefix='Normal';
enb.CellRefP=Nt;
enb.TotSubframes=1;
cfg.Seed = 1; % Random channel seed
cfg.NRxAnts = Nr; % 1 receive antenna
cfg.DelayProfile = 'ETU'; % EVA delay spread
cfg.DopplerFreq = 100; % 120Hz Doppler frequency
cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation
cfg.InitTime = 0; % Initialize at time zero
cfg.NTerms = 16; % Oscillators used in fading model
cfg.ModelType = 'GMEDS'; % Rayleigh fading model type
cfg.InitPhase = 'Random'; % Random initial phases
cfg.NormalizePathGains = 'On'; % Normalize delay profile power
cfg.NormalizeTxAnts = 'On'; % Normalize for transmit antennas
cec = struct('FreqWindow',9,'TimeWindow',9,'InterpType','cubic');
cec.PilotAverage = 'UserDefined';
cec.InterpWinSize = 1;
cec.InterpWindow = 'Causal';
sym = 2*rand(Ns*Nl,1)-1;
layermap = lteLayerMap(sym, Nl, txscheme);
tx = lteDLPrecode(layermap, Nt, txscheme, codebook);
tx_srs = srslte_precoder(sym, Nl, Nt, txscheme);
err_tx=mean(abs(tx_srs-tx).^2)
[txwaveform, info] = lteOFDMModulate(enb, reshape(tx,enb.NDLRB*12,[],Nt));
cfg.SamplingRate = info.SamplingRate;
rxwaveform = lteFadingChannel(cfg, txwaveform);
rxGrid = lteOFDMDemodulate(enb, rxwaveform);
h=lteDLPerfectChannelEstimate(enb, cfg);
hp=reshape(h,Ns,Nr,Nt);
rx=reshape(rxGrid,Ns,Nr);
if (Nt > 1)
if (strcmp(txscheme,'TxDiversity')==1)
output_mat = lteTransmitDiversityDecode(rx, hp);
elseif (strcmp(txscheme,'CDD')==1 || strcmp(txscheme,'SpatialMux')==1)
pdsch.NLayers=Nl;
pdsch.RNTI=0;
pdsch.TxScheme=txscheme;
pdsch.PMISet=codebook;
pdsch.NCodewords=Ncw;
deprecoded = lteEqualizeMIMO(enb,pdsch,rx,hp,0);
out_cw = lteLayerDemap(pdsch,deprecoded);
output_mat = [];
for i=1:Ncw
output_mat = [output_mat out_cw{i}];
end
else
error('Unsupported txscheme')
end
else
output_mat = lteEqualizeMMSE(rx, hp, 0);
end
output_srs = srslte_predecoder(rx, hp, 0, txscheme);
plot(abs(output_mat(:)-output_srs(:)))
mean(abs(output_mat(:)-output_srs(:)).^2)
t=1:100;
plot(t,real(output_mat(t)),t,real(output_srs(t)))

View File

@ -129,9 +129,10 @@ void sig_int_handler(int signo)
}
}
int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *q) {
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *q) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv(h, data, nsamples, 1);
return srslte_rf_recv(h, data[0], nsamples, 1);
}
enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state;
@ -141,7 +142,7 @@ enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state;
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL, NULL};
prog_args_t prog_args;
srslte_cell_t cell;
int64_t sf_cnt;
@ -180,6 +181,8 @@ int main(int argc, char **argv) {
}
srslte_rf_set_rx_gain(&rf, 50);
}
sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
sigset_t sigset;
sigemptyset(&sigset);
@ -198,7 +201,7 @@ int main(int argc, char **argv) {
uint32_t ntrial=0;
do {
ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo);
ret = rf_search_and_decode_mib(&rf, 1, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo);
if (ret < 0) {
fprintf(stderr, "Error searching for cell\n");
exit(-1);
@ -234,11 +237,11 @@ int main(int argc, char **argv) {
srslte_rf_stop_rx_stream(&rf);
srslte_rf_flush_buffer(&rf);
if (srslte_ue_sync_init(&ue_sync, cell, srslte_rf_recv_wrapper, (void*) &rf)) {
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) {
fprintf(stderr, "Error initiating ue_sync\n");
return -1;
}
if (srslte_ue_dl_init(&ue_dl, cell)) {
if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) {
fprintf(stderr, "Error initiating UE downlink processing module\n");
return -1;
}
@ -280,7 +283,7 @@ int main(int argc, char **argv) {
/* Main loop */
while ((sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) && !go_exit) {
ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer);
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
}
@ -292,7 +295,7 @@ int main(int argc, char **argv) {
case DECODE_MIB:
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
srslte_pbch_decode_reset(&ue_mib.pbch);
n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset);
n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset);
if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n");
return -1;
@ -307,7 +310,7 @@ int main(int argc, char **argv) {
case DECODE_SIB:
/* We are looking for SI Blocks, search only in appropiate places */
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
n = srslte_ue_dl_decode_multi(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
return -1;
@ -329,11 +332,11 @@ int main(int argc, char **argv) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 5) {
/* Run FFT for all subframe data */
srslte_ofdm_rx_sf(&fft, sf_buffer, sf_symbols);
srslte_ofdm_rx_sf(&fft, sf_buffer[0], sf_symbols);
srslte_chest_dl_estimate(&chest, sf_symbols, ce, srslte_ue_sync_get_sfidx(&ue_sync));
rssi = SRSLTE_VEC_EMA(srslte_vec_avg_power_cf(sf_buffer,SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))),rssi,0.05);
rssi = SRSLTE_VEC_EMA(srslte_vec_avg_power_cf(sf_buffer[0],SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))),rssi,0.05);
rssi_utra = SRSLTE_VEC_EMA(srslte_chest_dl_get_rssi(&chest),rssi_utra,0.05);
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&chest),rsrq,0.05);
rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&chest),rsrp,0.05);

View File

@ -120,9 +120,13 @@ void parse_args(int argc, char **argv) {
}
}
int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) {
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv((srslte_rf_t*) h, data, nsamples, 1);
void *ptr[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ptr[i] = data[i];
}
return srslte_rf_recv_with_time_multi((srslte_rf_t*) h, ptr, nsamples, 1, NULL, NULL);
}
bool go_exit = false;
@ -200,7 +204,7 @@ int main(int argc, char **argv) {
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, cell_detect_config.max_frames_pss, srslte_rf_recv_wrapper, (void*) &rf)) {
if (srslte_ue_cellsearch_init_multi(&cs, cell_detect_config.max_frames_pss, srslte_rf_recv_wrapper, 1, (void*) &rf)) {
fprintf(stderr, "Error initiating UE cell detect\n");
exit(-1);
}
@ -228,7 +232,7 @@ int main(int argc, char **argv) {
srslte_cell_t cell;
cell.id = found_cells[i].cell_id;
cell.cp = found_cells[i].cp;
int ret = rf_mib_decoder(&rf, &cell_detect_config, &cell, NULL);
int ret = rf_mib_decoder(&rf, 1, &cell_detect_config, &cell, NULL);
if (ret < 0) {
fprintf(stderr, "Error decoding MIB\n");
exit(-1);

View File

@ -89,6 +89,7 @@ typedef struct {
uint32_t file_nof_ports;
uint32_t file_cell_id;
char *rf_args;
uint32_t rf_nof_rx_ant;
double rf_freq;
float rf_gain;
int net_port;
@ -113,6 +114,7 @@ void args_default(prog_args_t *args) {
args->file_offset_freq = 0;
args->rf_args = "";
args->rf_freq = -1.0;
args->rf_nof_rx_ant = 1;
#ifdef ENABLE_AGC_DEFAULT
args->rf_gain = -1.0;
#else
@ -128,6 +130,7 @@ void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [agpPoOcildDnruv] -f rx_frequency (in Hz) | -i input_file\n", prog);
#ifndef DISABLE_RF
printf("\t-a RF args [Default %s]\n", args->rf_args);
printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant);
#ifdef ENABLE_AGC_DEFAULT
printf("\t-g RF fix RX gain [Default AGC]\n");
#else
@ -163,7 +166,7 @@ void usage(prog_args_t *args, char *prog) {
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aoglipPcOCtdDnvrfuUsS")) != -1) {
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsS")) != -1) {
switch (opt) {
case 'i':
args->input_file_name = argv[optind];
@ -186,6 +189,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'a':
args->rf_args = argv[optind];
break;
case 'A':
args->rf_nof_rx_ant = atoi(argv[optind]);
break;
case 'g':
args->rf_gain = atof(argv[optind]);
break;
@ -252,10 +258,16 @@ void sig_int_handler(int signo)
}
}
cf_t *sf_buffer[2] = {NULL, NULL};
#ifndef DISABLE_RF
int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) {
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv(h, data, nsamples, 1);
void *ptr[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ptr[i] = data[i];
}
return srslte_rf_recv_with_time_multi(h, ptr, nsamples, true, NULL, NULL);
}
double srslte_rf_set_rx_gain_th_wrapper_(void *h, double f) {
@ -273,7 +285,6 @@ srslte_ue_sync_t ue_sync;
prog_args_t prog_args;
uint32_t sfn = 0; // system frame number
cf_t *sf_buffer = NULL;
srslte_netsink_t net_sink, net_sink_signal;
int main(int argc, char **argv) {
@ -311,8 +322,8 @@ int main(int argc, char **argv) {
#ifndef DISABLE_RF
if (!prog_args.input_file_name) {
printf("Opening RF device...\n");
if (srslte_rf_open(&rf, prog_args.rf_args)) {
printf("Opening RF device with %d RX antennas...\n", prog_args.rf_nof_rx_ant);
if (srslte_rf_open_multi(&rf, prog_args.rf_args, prog_args.rf_nof_rx_ant)) {
fprintf(stderr, "Error opening rf\n");
exit(-1);
}
@ -344,7 +355,7 @@ int main(int argc, char **argv) {
uint32_t ntrial=0;
do {
ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo);
ret = rf_search_and_decode_mib(&rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo);
if (ret < 0) {
fprintf(stderr, "Error searching for cell\n");
exit(-1);
@ -356,6 +367,10 @@ int main(int argc, char **argv) {
if (go_exit) {
exit(0);
}
srslte_rf_stop_rx_stream(&rf);
srslte_rf_flush_buffer(&rf);
/* set sampling frequency */
int srate = srslte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
@ -376,8 +391,6 @@ int main(int argc, char **argv) {
}
INFO("Stopping RF and flushing buffer...\r",0);
srslte_rf_stop_rx_stream(&rf);
srslte_rf_flush_buffer(&rf);
}
#endif
@ -399,7 +412,7 @@ int main(int argc, char **argv) {
} else {
#ifndef DISABLE_RF
if (srslte_ue_sync_init(&ue_sync, cell, srslte_rf_recv_wrapper, (void*) &rf)) {
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, prog_args.rf_nof_rx_ant, (void*) &rf)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
@ -411,11 +424,15 @@ int main(int argc, char **argv) {
exit(-1);
}
if (srslte_ue_dl_init(&ue_dl, cell)) { // This is the User RNTI
if (srslte_ue_dl_init_multi(&ue_dl, cell, prog_args.rf_nof_rx_ant)) { // This is the User RNTI
fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1);
}
for (int i=0;i<prog_args.rf_nof_rx_ant;i++) {
sf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti);
@ -462,7 +479,7 @@ int main(int argc, char **argv) {
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer);
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
}
@ -477,7 +494,7 @@ int main(int argc, char **argv) {
switch (state) {
case DECODE_MIB:
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset);
n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset);
if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n");
exit(-1);
@ -503,10 +520,10 @@ int main(int argc, char **argv) {
}
if (decode_pdsch) {
INFO("Attempting DL decode SFN=%d\n", sfn);
n = srslte_ue_dl_decode(&ue_dl,
&sf_buffer[prog_args.time_offset],
data,
sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
n = srslte_ue_dl_decode_multi(&ue_dl,
sf_buffer,
data,
sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
if (n < 0) {
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);

View File

@ -98,13 +98,13 @@ void parse_args(int argc, char **argv) {
}
}
int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) {
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv(h, data, nsamples, 1);
return srslte_rf_recv(h, data[2], nsamples, 1);
}
int main(int argc, char **argv) {
cf_t *buffer;
cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL, NULL};
int n;
srslte_rf_t rf;
srslte_filesink_t sink;
@ -124,6 +124,8 @@ int main(int argc, char **argv) {
}
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
@ -156,7 +158,7 @@ int main(int argc, char **argv) {
cell.nof_prb = nof_prb;
cell.nof_ports = 1;
if (srslte_ue_sync_init(&ue_sync, cell, srslte_rf_recv_wrapper, (void*) &rf)) {
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
@ -167,7 +169,7 @@ int main(int argc, char **argv) {
while((subframe_count < nof_subframes || nof_subframes == -1)
&& !stop_capture)
{
n = srslte_ue_sync_get_buffer(&ue_sync, &buffer);
n = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer);
if (n < 0) {
fprintf(stderr, "Error receiving samples\n");
exit(-1);
@ -179,7 +181,7 @@ int main(int argc, char **argv) {
}
} else {
printf("Writing to file %6d subframes...\r", subframe_count);
srslte_filesink_write(&sink, buffer, SRSLTE_SF_LEN_PRB(nof_prb));
srslte_filesink_write(&sink, buffer[0], SRSLTE_SF_LEN_PRB(nof_prb));
subframe_count++;
}
}

View File

@ -76,9 +76,9 @@ typedef struct {
srslte_interp_linsrslte_vec_t srslte_interp_linvec;
srslte_interp_lin_t srslte_interp_lin;
float rssi[SRSLTE_MAX_PORTS];
float rsrp[SRSLTE_MAX_PORTS];
float noise_estimate[SRSLTE_MAX_PORTS];
float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
/* Use PSS for noise estimation in LS linear interpolation mode */
cf_t pss_signal[SRSLTE_PSS_LEN];
@ -86,6 +86,7 @@ typedef struct {
cf_t tmp_pss_noisy[SRSLTE_PSS_LEN];
srslte_chest_dl_noise_alg_t noise_alg;
int last_nof_antennas;
} srslte_chest_dl_t;
@ -105,6 +106,12 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q,
SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
srslte_chest_dl_noise_alg_t noise_estimation_alg);
SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t *q,
cf_t *input,
cf_t *ce[SRSLTE_MAX_PORTS],
@ -114,7 +121,8 @@ SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q,
cf_t *input,
cf_t *ce,
uint32_t sf_idx,
uint32_t port_id);
uint32_t port_id,
uint32_t rxant_id);
SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q);

View File

@ -50,7 +50,7 @@
#define SRSLTE_PC_MAX 23 // Maximum TX power for Category 1 UE (in dBm)
#define SRSLTE_MAX_PORTS 4
#define SRSLTE_MAX_LAYERS 8
#define SRSLTE_MAX_LAYERS 4
#define SRSLTE_MAX_CODEWORDS 2
#define SRSLTE_LTE_CRC24A 0x1864CFB
@ -167,7 +167,8 @@ typedef struct SRSLTE_API {
typedef enum SRSLTE_API {
SRSLTE_MIMO_TYPE_SINGLE_ANTENNA,
SRSLTE_MIMO_TYPE_TX_DIVERSITY,
SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX
SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX,
SRSLTE_MIMO_TYPE_CDD
} srslte_mimo_type_t;
typedef enum SRSLTE_API {

View File

@ -70,12 +70,26 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
int nof_symbols,
float noise_estimate);
SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x,
int nof_rxant,
int nof_symbols,
float noise_estimate);
SRSLTE_API int srslte_predecoding_diversity(cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports,
int nof_symbols);
SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant,
int nof_ports,
int nof_symbols);
SRSLTE_API int srslte_predecoding_type(cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],

View File

@ -51,12 +51,14 @@
typedef struct SRSLTE_API {
srslte_cell_t cell;
int nof_symbols;
uint32_t nof_rx_antennas;
/* handler to REGs resource mapper */
srslte_regs_t *regs;
/* buffers */
cf_t ce[SRSLTE_MAX_PORTS][PCFICH_RE];
cf_t ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS][PCFICH_RE];
cf_t symbols[SRSLTE_MAX_PORTS][PCFICH_RE];
cf_t x[SRSLTE_MAX_PORTS][PCFICH_RE];
cf_t d[PCFICH_RE];
@ -80,6 +82,11 @@ SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q,
srslte_regs_t *regs,
srslte_cell_t cell);
SRSLTE_API int srslte_pcfich_init_multi(srslte_pcfich_t *q,
srslte_regs_t *regs,
srslte_cell_t cell,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_pcfich_free(srslte_pcfich_t *q);
SRSLTE_API int srslte_pcfich_decode(srslte_pcfich_t *q,
@ -90,6 +97,14 @@ SRSLTE_API int srslte_pcfich_decode(srslte_pcfich_t *q,
uint32_t *cfi,
float *corr_result);
SRSLTE_API int srslte_pcfich_decode_multi(srslte_pcfich_t *q,
cf_t *sf_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint32_t subframe,
uint32_t *cfi,
float *corr_result);
SRSLTE_API int srslte_pcfich_encode(srslte_pcfich_t *q,
uint32_t cfi,
cf_t *sf_symbols[SRSLTE_MAX_PORTS],

View File

@ -63,11 +63,12 @@ typedef struct SRSLTE_API {
uint32_t nof_regs;
uint32_t nof_cce;
uint32_t max_bits;
uint32_t nof_rx_antennas;
srslte_regs_t *regs;
/* buffers */
cf_t *ce[SRSLTE_MAX_PORTS];
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *symbols[SRSLTE_MAX_PORTS];
cf_t *x[SRSLTE_MAX_PORTS];
cf_t *d;
@ -87,6 +88,11 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q,
srslte_regs_t *regs,
srslte_cell_t cell);
SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q,
srslte_regs_t *regs,
srslte_cell_t cell,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q);
@ -113,6 +119,13 @@ SRSLTE_API int srslte_pdcch_extract_llr(srslte_pdcch_t *q,
uint32_t nsubframe,
uint32_t cfi);
SRSLTE_API int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q,
cf_t *sf_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint32_t nsubframe,
uint32_t cfi);
/* Decoding functions: Try to decode a DCI message after calling srslte_pdcch_extract_llr */
SRSLTE_API int srslte_pdcch_decode_msg(srslte_pdcch_t *q,
srslte_dci_msg_t *msg,

View File

@ -55,11 +55,13 @@ typedef struct {
typedef struct SRSLTE_API {
srslte_cell_t cell;
uint32_t nof_rx_antennas;
uint32_t max_re;
/* buffers */
// void buffers are shared for tx and rx
cf_t *ce[SRSLTE_MAX_PORTS];
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *symbols[SRSLTE_MAX_PORTS];
cf_t *x[SRSLTE_MAX_PORTS];
cf_t *d;
@ -78,6 +80,10 @@ typedef struct SRSLTE_API {
SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q,
srslte_cell_t cell);
SRSLTE_API int srslte_pdsch_init_multi(srslte_pdsch_t *q,
srslte_cell_t cell,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q);
SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q,
@ -112,6 +118,15 @@ SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q,
uint16_t rnti,
uint8_t *data);
SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint16_t rnti,
uint8_t *data);
SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q);
SRSLTE_API uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q);

View File

@ -62,12 +62,14 @@
typedef struct SRSLTE_API {
srslte_cell_t cell;
uint32_t nof_rx_antennas;
/* handler to REGs resource mapper */
srslte_regs_t *regs;
/* buffers */
cf_t ce[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB];
cf_t symbols[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB];
cf_t ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB];
cf_t sf_symbols[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB];
cf_t x[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB];
cf_t d[SRSLTE_PHICH_MAX_NSYMB];
cf_t d0[SRSLTE_PHICH_MAX_NSYMB];
@ -87,6 +89,11 @@ SRSLTE_API int srslte_phich_init(srslte_phich_t *q,
srslte_regs_t *regs,
srslte_cell_t cell);
SRSLTE_API int srslte_phich_init_multi(srslte_phich_t *q,
srslte_regs_t *regs,
srslte_cell_t cell,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_phich_free(srslte_phich_t *q);
SRSLTE_API void srslte_phich_calc(srslte_phich_t *q,
@ -105,6 +112,16 @@ SRSLTE_API int srslte_phich_decode(srslte_phich_t *q,
uint8_t *ack,
float *distance);
SRSLTE_API int srslte_phich_decode_multi(srslte_phich_t *q,
cf_t *slot_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint32_t ngroup,
uint32_t nseq,
uint32_t nsubframe,
uint8_t *ack,
float *distance);
SRSLTE_API int srslte_phich_encode(srslte_phich_t *q,
uint8_t ack,
uint32_t ngroup,

View File

@ -71,9 +71,18 @@ typedef void (*srslte_rf_error_handler_t)(srslte_rf_error_t error);
SRSLTE_API int srslte_rf_open(srslte_rf_t *h,
char *args);
SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h,
char *args,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
char *devname,
char *args);
char *devname,
char *args);
SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h,
char *devname,
char *args,
uint32_t nof_rx_antennas);
SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h);
@ -139,6 +148,13 @@ SRSLTE_API int srslte_rf_recv_with_time(srslte_rf_t *h,
time_t *secs,
double *frac_secs);
SRSLTE_API int srslte_rf_recv_with_time_multi(srslte_rf_t *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
SRSLTE_API double srslte_rf_set_tx_srate(srslte_rf_t *h,
double freq);

View File

@ -43,17 +43,20 @@ SRSLTE_API int rf_rssi_scan(srslte_rf_t *rf,
int nsamp);
SRSLTE_API int rf_mib_decoder(srslte_rf_t *rf,
uint32_t nof_rx_antennas,
cell_search_cfg_t *config,
srslte_cell_t *cell,
float *cfo);
SRSLTE_API int rf_cell_search(srslte_rf_t *rf,
uint32_t nof_rx_antennas,
cell_search_cfg_t *config,
int force_N_id_2,
srslte_cell_t *cell,
float *cfo);
SRSLTE_API int rf_search_and_decode_mib(srslte_rf_t *rf,
uint32_t nof_rx_antennas,
cell_search_cfg_t *config,
int force_N_id_2,
srslte_cell_t *cell,

View File

@ -69,6 +69,9 @@ typedef struct SRSLTE_API {
typedef struct SRSLTE_API {
srslte_ue_sync_t ue_sync;
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
uint32_t nof_rx_antennas;
uint32_t max_frames;
uint32_t nof_valid_frames; // number of 5 ms frames to scan
@ -83,6 +86,12 @@ SRSLTE_API int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t *q,
int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*),
void *stream_handler);
SRSLTE_API int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t *q,
uint32_t max_frames_total,
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void *stream_handler);
SRSLTE_API void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t *q);
SRSLTE_API int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t *q,

View File

@ -88,8 +88,12 @@ typedef struct SRSLTE_API {
srslte_ra_dl_dci_t dl_dci;
srslte_cell_t cell;
cf_t *sf_symbols;
cf_t *ce[SRSLTE_MAX_PORTS];
uint32_t nof_rx_antennas;
cf_t *sf_symbols; // this is for backwards compatibility
cf_t *sf_symbols_m[SRSLTE_MAX_PORTS];
cf_t *ce[SRSLTE_MAX_PORTS]; // compatibility
cf_t *ce_m[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
srslte_dci_format_t dci_format;
uint64_t pkt_errors;
@ -112,6 +116,10 @@ typedef struct SRSLTE_API {
SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q,
srslte_cell_t cell);
SRSLTE_API int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
srslte_cell_t cell,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
@ -119,6 +127,11 @@ SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
uint32_t sf_idx,
uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
uint32_t sf_idx,
uint32_t *cfi);
@ -158,12 +171,23 @@ SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q,
uint8_t *data,
uint32_t tti);
SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data,
uint32_t tti);
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q,
cf_t *input,
uint8_t *data,
uint32_t tti,
uint16_t rnti);
SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data,
uint32_t tti,
uint16_t rnti);
SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q,
uint32_t sf_idx,
uint32_t n_prb_lowest,

View File

@ -100,14 +100,23 @@ SRSLTE_API int srslte_ue_mib_decode(srslte_ue_mib_t * q,
typedef struct {
srslte_ue_mib_t ue_mib;
srslte_ue_sync_t ue_sync;
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
uint32_t nof_rx_antennas;
} srslte_ue_mib_sync_t;
SRSLTE_API int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q,
uint32_t cell_id,
srslte_cp_t cp,
int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t *),
int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t *),
void *stream_handler);
SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q,
uint32_t cell_id,
srslte_cp_t cp,
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t *),
uint32_t nof_rx_antennas,
void *stream_handler);
SRSLTE_API void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q);
SRSLTE_API void srslte_ue_mib_sync_reset(srslte_ue_mib_sync_t * q);

View File

@ -75,9 +75,12 @@ typedef struct SRSLTE_API {
uint32_t agc_period;
void *stream;
int (*recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*);
int (*recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*);
int (*recv_callback_single)(void*, void*, uint32_t, srslte_timestamp_t*);
srslte_timestamp_t last_timestamp;
uint32_t nof_rx_antennas;
srslte_filesource_t file_source;
bool file_mode;
float file_cfo;
@ -85,8 +88,6 @@ typedef struct SRSLTE_API {
srslte_ue_sync_state_t state;
cf_t *input_buffer;
uint32_t frame_len;
uint32_t fft_size;
uint32_t nof_recv_sf; // Number of subframes received each call to srslte_ue_sync_get_buffer
@ -115,18 +116,24 @@ typedef struct SRSLTE_API {
float mean_sfo;
uint32_t sample_offset_correct_period;
float sfo_ema;
#ifdef MEASURE_EXEC_TIME
float mean_exec_time;
#endif
} srslte_ue_sync_t;
SRSLTE_API int srslte_ue_sync_init(srslte_ue_sync_t *q,
srslte_cell_t cell,
int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*),
void *stream_handler);
SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
srslte_cell_t cell,
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void *stream_handler);
SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q,
uint32_t nof_prb,
char *file_name,
@ -141,9 +148,6 @@ SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q,
SRSLTE_API uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q);
SRSLTE_API int srslte_ue_sync_get_buffer(srslte_ue_sync_t *q,
cf_t **sf_symbols);
SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q,
uint32_t period);
@ -151,6 +155,9 @@ SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q,
SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q,
cf_t *input_buffer);
SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q,
cf_t *input_buffer[SRSLTE_MAX_PORTS]);
SRSLTE_API void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q,
float cfo);

View File

@ -311,7 +311,7 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id)
return rssi/nsymbols;
}
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id)
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id)
{
/* Get references from the input signal */
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
@ -331,41 +331,61 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u
/* Estimate noise power */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) {
q->noise_estimate[port_id] = estimate_noise_pilots(q, port_id);
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id);
} else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[port_id] = estimate_noise_pss(q, input, ce);
q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce);
}
} else {
if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[port_id] = estimate_noise_empty_sc(q, input);
q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input);
}
}
}
/* Compute RSRP for the channel estimates in this port */
q->rsrp[port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
if (port_id == 0) {
/* compute rssi only for port 0 */
q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id);
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
}
return 0;
}
int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas)
{
for (uint32_t rxant_id=0;rxant_id<nof_rx_antennas;rxant_id++) {
for (uint32_t port_id=0;port_id<q->cell.nof_ports;port_id++) {
if (srslte_chest_dl_estimate_port(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id)) {
return SRSLTE_ERROR;
}
}
}
q->last_nof_antennas = nof_rx_antennas;
return SRSLTE_SUCCESS;
}
int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx)
{
uint32_t port_id;
for (port_id=0;port_id<q->cell.nof_ports;port_id++) {
srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id);
if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) {
return SRSLTE_ERROR;
}
}
q->last_nof_antennas = 1;
return SRSLTE_SUCCESS;
}
float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) {
return srslte_vec_acc_ff(q->noise_estimate, q->cell.nof_ports)/q->cell.nof_ports;
float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) {
n += srslte_vec_acc_ff(q->noise_estimate[i], q->cell.nof_ports)/q->cell.nof_ports;
}
return n/q->last_nof_antennas;
}
float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) {
@ -378,20 +398,31 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) {
}
float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) {
return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE;
float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) {
n += 4*q->rssi[i][0]/q->cell.nof_prb/SRSLTE_NRE;
}
return n/q->last_nof_antennas;
}
/* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb is the average power per PRB
* q->rsrp[0] is the average power of RE containing references only (for port 0).
*/
float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) {
return q->cell.nof_prb*q->rsrp[0] / q->rssi[0];
float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) {
n += q->cell.nof_prb*q->rsrp[i][0] / q->rssi[i][0];
}
return n/q->last_nof_antennas;
}
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
// return sum of power received from all tx ports
return srslte_vec_acc_ff(q->rsrp, q->cell.nof_ports);
float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) {
n += srslte_vec_acc_ff(q->rsrp[i], q->cell.nof_ports)/q->cell.nof_ports;
}
return n/q->last_nof_antennas;
}

View File

@ -161,7 +161,7 @@ int main(int argc, char **argv) {
struct timeval t[3];
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port);
srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port, 0);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);

View File

@ -117,6 +117,9 @@ int srslte_layermap_type(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_LAYER
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
return srslte_layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols);
break;
case SRSLTE_MIMO_TYPE_CDD:
fprintf(stderr, "CDD Not implemented\n");
return -1;
}
return 0;
}
@ -208,6 +211,9 @@ int srslte_layerdemap_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *d[SRSLTE_MAX_CODEWO
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
return srslte_layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols);
break;
case SRSLTE_MIMO_TYPE_CDD:
fprintf(stderr, "CDD Not implemented\n");
return -1;
}
return 0;
}

View File

@ -37,13 +37,13 @@
#ifdef LV_HAVE_SSE
#include <xmmintrin.h>
#include <pmmintrin.h>
int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate);
int srslte_predecoding_diversity2_sse(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_symbols);
int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate);
int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols);
#endif
#ifdef LV_HAVE_AVX
#include <immintrin.h>
int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate);
int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate);
#endif
@ -58,46 +58,82 @@ int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl
#define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b)))
int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) {
int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) {
float *xPtr = (float*) x;
const float *hPtr = (const float*) h;
const float *yPtr = (const float*) y;
const float *hPtr1 = (const float*) h[0];
const float *yPtr1 = (const float*) y[0];
const float *hPtr2 = (const float*) h[1];
const float *yPtr2 = (const float*) y[1];
__m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f);
__m128 noise = _mm_set1_ps(noise_estimate);
__m128 h1Val, h2Val, y1Val, y2Val, h12square, h1square, h2square, h1conj, h2conj, x1Val, x2Val;
__m128 h1Val1, h2Val1, y1Val1, y2Val1;
__m128 h1Val2, h2Val2, y1Val2, y2Val2;
__m128 hsquare, h1square, h2square, h1conj1, h2conj1, x1Val1, x2Val1;
__m128 hsquare2, h1conj2, h2conj2, x1Val2, x2Val2;
for (int i=0;i<nof_symbols/4;i++) {
y1Val = _mm_load_ps(yPtr); yPtr+=4;
y2Val = _mm_load_ps(yPtr); yPtr+=4;
h1Val = _mm_load_ps(hPtr); hPtr+=4;
h2Val = _mm_load_ps(hPtr); hPtr+=4;
h12square = _mm_hadd_ps(_mm_mul_ps(h1Val, h1Val), _mm_mul_ps(h2Val, h2Val));
if (noise_estimate > 0) {
h12square = _mm_add_ps(h12square, noise);
y1Val1 = _mm_load_ps(yPtr1); yPtr1+=4;
y2Val1 = _mm_load_ps(yPtr1); yPtr1+=4;
h1Val1 = _mm_load_ps(hPtr1); hPtr1+=4;
h2Val1 = _mm_load_ps(hPtr1); hPtr1+=4;
if (nof_rxant == 2) {
y1Val2 = _mm_load_ps(yPtr2); yPtr2+=4;
y2Val2 = _mm_load_ps(yPtr2); yPtr2+=4;
h1Val2 = _mm_load_ps(hPtr2); hPtr2+=4;
h2Val2 = _mm_load_ps(hPtr2); hPtr2+=4;
}
h1square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(1, 1, 0, 0));
h2square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(3, 3, 2, 2));
hsquare = _mm_hadd_ps(_mm_mul_ps(h1Val1, h1Val1), _mm_mul_ps(h2Val1, h2Val1));
if (nof_rxant == 2) {
hsquare2 = _mm_hadd_ps(_mm_mul_ps(h1Val2, h1Val2), _mm_mul_ps(h2Val2, h2Val2));
hsquare = _mm_add_ps(hsquare, hsquare2);
}
if (noise_estimate > 0) {
hsquare = _mm_add_ps(hsquare, noise);
}
h1square = _mm_shuffle_ps(hsquare, hsquare, _MM_SHUFFLE(1, 1, 0, 0));
h2square = _mm_shuffle_ps(hsquare, hsquare, _MM_SHUFFLE(3, 3, 2, 2));
/* Conjugate channel */
h1conj = _mm_xor_ps(h1Val, conjugator);
h2conj = _mm_xor_ps(h2Val, conjugator);
h1conj1 = _mm_xor_ps(h1Val1, conjugator);
h2conj1 = _mm_xor_ps(h2Val1, conjugator);
/* Complex product */
x1Val = PROD(y1Val, h1conj);
x2Val = PROD(y2Val, h2conj);
x1Val = _mm_div_ps(x1Val, h1square);
x2Val = _mm_div_ps(x2Val, h2square);
if (nof_rxant == 2) {
h1conj2 = _mm_xor_ps(h1Val2, conjugator);
h2conj2 = _mm_xor_ps(h2Val2, conjugator);
}
/* Complex product */
x1Val1 = PROD(y1Val1, h1conj1);
x2Val1 = PROD(y2Val1, h2conj1);
if (nof_rxant == 2) {
x1Val2 = PROD(y1Val2, h1conj2);
x2Val2 = PROD(y2Val2, h2conj2);
x1Val1 = _mm_add_ps(x1Val1, x1Val2);
x2Val1 = _mm_add_ps(x2Val1, x2Val2);
}
x1Val1 = _mm_div_ps(x1Val1, h1square);
x2Val1 = _mm_div_ps(x2Val1, h2square);
_mm_store_ps(xPtr, x1Val1); xPtr+=4;
_mm_store_ps(xPtr, x2Val1); xPtr+=4;
_mm_store_ps(xPtr, x1Val); xPtr+=4;
_mm_store_ps(xPtr, x2Val); xPtr+=4;
}
for (int i=8*(nof_symbols/8);i<nof_symbols;i++) {
x[i] = y[i]*conj(h[i])/(conj(h[i])*h[i]+noise_estimate);
cf_t r = 0;
cf_t hh = 0;
for (int p=0;p<nof_rxant;p++) {
r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i];
}
x[i] = r/(hh+noise_estimate);
}
return nof_symbols;
}
@ -110,42 +146,70 @@ int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl
int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) {
int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) {
float *xPtr = (float*) x;
const float *hPtr = (const float*) h;
const float *yPtr = (const float*) y;
const float *hPtr1 = (const float*) h[0];
const float *yPtr1 = (const float*) y[0];
const float *hPtr2 = (const float*) h[1];
const float *yPtr2 = (const float*) y[1];
__m256 conjugator = _mm256_setr_ps(0, -0.f, 0, -0.f, 0, -0.f, 0, -0.f);
__m256 noise = _mm256_set1_ps(noise_estimate);
__m256 h1Val, h2Val, y1Val, y2Val, h12square, h1square, h2square, h1_p, h2_p, h1conj, h2conj, x1Val, x2Val;
__m256 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val;
__m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2;
for (int i=0;i<nof_symbols/8;i++) {
y1Val = _mm256_load_ps(yPtr); yPtr+=8;
y2Val = _mm256_load_ps(yPtr); yPtr+=8;
h1Val = _mm256_load_ps(hPtr); hPtr+=8;
h2Val = _mm256_load_ps(hPtr); hPtr+=8;
y1Val1 = _mm256_load_ps(yPtr1); yPtr1+=8;
y2Val1 = _mm256_load_ps(yPtr1); yPtr1+=8;
h1Val1 = _mm256_load_ps(hPtr1); hPtr1+=8;
h2Val1 = _mm256_load_ps(hPtr1); hPtr1+=8;
if (nof_rxant == 2) {
y1Val2 = _mm256_load_ps(yPtr2); yPtr2+=8;
y2Val2 = _mm256_load_ps(yPtr2); yPtr2+=8;
h1Val2 = _mm256_load_ps(hPtr2); hPtr2+=8;
h2Val2 = _mm256_load_ps(hPtr2); hPtr2+=8;
}
__m256 t1 = _mm256_mul_ps(h1Val, h1Val);
__m256 t2 = _mm256_mul_ps(h2Val, h2Val);
__m256 t1 = _mm256_mul_ps(h1Val1, h1Val1);
__m256 t2 = _mm256_mul_ps(h2Val1, h2Val1);
h12square = _mm256_hadd_ps(_mm256_permute2f128_ps(t1, t2, 0x20), _mm256_permute2f128_ps(t1, t2, 0x31));
if (nof_rxant == 2) {
t1 = _mm256_mul_ps(h1Val2, h1Val2);
t2 = _mm256_mul_ps(h2Val2, h2Val2);
h12square = _mm256_add_ps(h12square, _mm256_hadd_ps(_mm256_permute2f128_ps(t1, t2, 0x20), _mm256_permute2f128_ps(t1, t2, 0x31)));
}
if (noise_estimate > 0) {
h12square = _mm256_add_ps(h12square, noise);
}
h1_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(1, 1, 0, 0));
h2_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(3, 3, 2, 2));
h1square = _mm256_permute2f128_ps(h1_p, h2_p, 2<<4);
h2square = _mm256_permute2f128_ps(h1_p, h2_p, 3<<4 | 1);
/* Conjugate channel */
h1conj = _mm256_xor_ps(h1Val, conjugator);
h2conj = _mm256_xor_ps(h2Val, conjugator);
h1conj1 = _mm256_xor_ps(h1Val1, conjugator);
h2conj1 = _mm256_xor_ps(h2Val1, conjugator);
if (nof_rxant == 2) {
h1conj2 = _mm256_xor_ps(h1Val2, conjugator);
h2conj2 = _mm256_xor_ps(h2Val2, conjugator);
}
/* Complex product */
x1Val = PROD_AVX(y1Val, h1conj);
x2Val = PROD_AVX(y2Val, h2conj);
x1Val = PROD_AVX(y1Val1, h1conj1);
x2Val = PROD_AVX(y2Val1, h2conj1);
if (nof_rxant == 2) {
x1Val = _mm256_add_ps(x1Val, PROD_AVX(y1Val2, h1conj2));
x2Val = _mm256_add_ps(x2Val, PROD_AVX(y2Val2, h2conj2));
}
x1Val = _mm256_div_ps(x1Val, h1square);
x2Val = _mm256_div_ps(x2Val, h2square);
@ -153,90 +217,143 @@ int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl
_mm256_store_ps(xPtr, x2Val); xPtr+=8;
}
for (int i=16*(nof_symbols/16);i<nof_symbols;i++) {
x[i] = y[i]*conj(h[i])/(conj(h[i])*h[i]+noise_estimate);
cf_t r = 0;
cf_t hh = 0;
for (int p=0;p<nof_rxant;p++) {
r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i];
}
x[i] = r/(hh+noise_estimate);
}
return nof_symbols;
}
#endif
int srslte_predecoding_single_gen(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) {
int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) {
for (int i=0;i<nof_symbols;i++) {
x[i] = y[i]*conj(h[i])/(conj(h[i])*h[i]+noise_estimate);
cf_t r = 0;
cf_t hh = 0;
for (int p=0;p<nof_rxant;p++) {
r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i];
}
x[i] = r/(hh+noise_estimate);
}
return nof_symbols;
}
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) {
int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, float noise_estimate) {
cf_t *y[SRSLTE_MAX_PORTS];
cf_t *h[SRSLTE_MAX_PORTS];
y[0] = y_;
h[0] = h_;
int nof_rxant = 1;
#ifdef LV_HAVE_AVX
if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate);
} else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate);
}
#else
#ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate);
} else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate);
}
#else
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate);
#endif
#endif
}
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) {
#ifdef LV_HAVE_AVX
if (nof_symbols > 32) {
return srslte_predecoding_single_avx(y, h, x, nof_symbols, noise_estimate);
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate);
} else {
return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate);
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate);
}
#else
#ifdef LV_HAVE_SSE
if (nof_symbols > 32) {
return srslte_predecoding_single_sse(y, h, x, nof_symbols, noise_estimate);
return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate);
} else {
return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate);
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate);
}
#else
return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate);
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate);
#endif
#endif
}
/* C implementatino of the SFBC equalizer */
int srslte_predecoding_diversity_gen_(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_symbols, int symbol_start)
int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols, int symbol_start)
{
int i;
if (nof_ports == 2) {
cf_t h00, h01, h10, h11, r0, r1;
float hh;
for (i = symbol_start/2; i < nof_symbols / 2; i++) {
h00 = h[0][2 * i];
h01 = h[0][2 * i+1];
h10 = h[1][2 * i];
h11 = h[1][2 * i+1];
hh = crealf(h00) * crealf(h00) + cimagf(h00) * cimagf(h00)
+ crealf(h11) * crealf(h11) + cimagf(h11) * cimagf(h11);
r0 = y[2 * i];
r1 = y[2 * i + 1];
if (hh == 0) {
hh = 1e-4;
float hh = 0;
cf_t x0 = 0;
cf_t x1 = 0;
for (int p=0;p<nof_rxant;p++) {
h00 = h[0][p][2 * i];
h01 = h[0][p][2 * i+1];
h10 = h[1][p][2 * i];
h11 = h[1][p][2 * i+1];
hh += crealf(h00) * crealf(h00) + cimagf(h00) * cimagf(h00)
+ crealf(h11) * crealf(h11) + cimagf(h11) * cimagf(h11);
r0 = y[p][2 * i];
r1 = y[p][2 * i + 1];
if (hh == 0) {
hh = 1e-4;
}
x0 += (conjf(h00) * r0 + h11 * conjf(r1));
x1 += (-h10 * conj(r0) + conj(h01) * r1);
}
x[0][i] = (conjf(h00) * r0 + h11 * conjf(r1)) / hh * sqrt(2);
x[1][i] = (-h10 * conj(r0) + conj(h01) * r1) / hh * sqrt(2);
x[0][i] = x0 / hh * sqrt(2);
x[1][i] = x1 / hh * sqrt(2);
}
return i;
} else if (nof_ports == 4) {
cf_t h0, h1, h2, h3, r0, r1, r2, r3;
float hh02, hh13;
int m_ap = (nof_symbols % 4) ? ((nof_symbols - 2) / 4) : nof_symbols / 4;
for (i = symbol_start; i < m_ap; i++) {
h0 = h[0][4 * i];
h1 = h[1][4 * i + 2];
h2 = h[2][4 * i];
h3 = h[3][4 * i + 2];
hh02 = crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0)
+ crealf(h2) * crealf(h2) + cimagf(h2) * cimagf(h2);
hh13 = crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1)
+ crealf(h3) * crealf(h3) + cimagf(h3) * cimagf(h3);
r0 = y[4 * i];
r1 = y[4 * i + 1];
r2 = y[4 * i + 2];
r3 = y[4 * i + 3];
x[0][i] = (conjf(h0) * r0 + h2 * conjf(r1)) / hh02 * sqrt(2);
x[1][i] = (-h2 * conjf(r0) + conjf(h0) * r1) / hh02 * sqrt(2);
x[2][i] = (conjf(h1) * r2 + h3 * conjf(r3)) / hh13 * sqrt(2);
x[3][i] = (-h3 * conjf(r2) + conjf(h1) * r3) / hh13 * sqrt(2);
float hh02 = 0, hh13 = 0;
cf_t x0 = 0, x1 = 0, x2 = 0, x3 = 0;
for (int p=0;p<nof_rxant;p++) {
h0 = h[0][p][4 * i];
h1 = h[1][p][4 * i + 2];
h2 = h[2][p][4 * i];
h3 = h[3][p][4 * i + 2];
hh02 += crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0)
+ crealf(h2) * crealf(h2) + cimagf(h2) * cimagf(h2);
hh13 += crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1)
+ crealf(h3) * crealf(h3) + cimagf(h3) * cimagf(h3);
r0 = y[p][4 * i];
r1 = y[p][4 * i + 1];
r2 = y[p][4 * i + 2];
r3 = y[p][4 * i + 3];
x0 += (conjf(h0) * r0 + h2 * conjf(r1));
x1 += (-h2 * conjf(r0) + conjf(h0) * r1);
x2 += (conjf(h1) * r2 + h3 * conjf(r3));
x3 += (-h3 * conjf(r2) + conjf(h1) * r3);
}
x[0][i] = x0 / hh02 * sqrt(2);
x[1][i] = x1 / hh02 * sqrt(2);
x[2][i] = x2 / hh13 * sqrt(2);
x[3][i] = x3 / hh13 * sqrt(2);
}
return i;
} else {
@ -245,86 +362,160 @@ int srslte_predecoding_diversity_gen_(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *
}
}
int srslte_predecoding_diversity_gen(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_symbols) {
return srslte_predecoding_diversity_gen_(y, h, x, nof_ports, nof_symbols, 0);
int srslte_predecoding_diversity_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols) {
return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0);
}
/* SSE implementation of the 2-port SFBC equalizer */
#ifdef LV_HAVE_SSE
int srslte_predecoding_diversity2_sse(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_symbols)
int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_symbols)
{
float *x0Ptr = (float*) x[0];
float *x1Ptr = (float*) x[1];
const float *h0Ptr = (const float*) h[0];
const float *h1Ptr = (const float*) h[1];
const float *yPtr = (const float*) y;
const float *h0Ptr0 = (const float*) h[0][0];
const float *h1Ptr0 = (const float*) h[1][0];
const float *h0Ptr1 = (const float*) h[0][1];
const float *h1Ptr1 = (const float*) h[1][1];
const float *yPtr0 = (const float*) y[0];
const float *yPtr1 = (const float*) y[1];
__m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f);
__m128 sqrt2 = _mm_setr_ps(sqrt(2), sqrt(2), sqrt(2), sqrt(2));
__m128 h0Val_0, h0Val_1, h1Val_0, h1Val_1, h00, h00conj, h01, h01conj, h10, h11, hh, hhshuf, hhsum, hhadd;
__m128 r0Val, r1Val, r0, r1, r0conj, r1conj;
__m128 h0Val_00, h0Val_10, h1Val_00, h1Val_10, h000, h00conj0, h010, h01conj0, h100, h110;
__m128 h0Val_01, h0Val_11, h1Val_01, h1Val_11, h001, h00conj1, h011, h01conj1, h101, h111;
__m128 hh, hhshuf, hhsum, hhadd;
__m128 r0Val0, r1Val0, r00, r10, r0conj0, r1conj0;
__m128 r0Val1, r1Val1, r01, r11, r0conj1, r1conj1;
__m128 x0, x1;
for (int i=0;i<nof_symbols/4;i++) {
h0Val_0 = _mm_load_ps(h0Ptr); h0Ptr+=4; h0Val_1 = _mm_load_ps(h0Ptr); h0Ptr+=4;
h1Val_0 = _mm_load_ps(h1Ptr); h1Ptr+=4; h1Val_1 = _mm_load_ps(h1Ptr); h1Ptr+=4;
h0Val_00 = _mm_load_ps(h0Ptr0); h0Ptr0+=4; h0Val_10 = _mm_load_ps(h0Ptr0); h0Ptr0+=4;
h1Val_00 = _mm_load_ps(h1Ptr0); h1Ptr0+=4; h1Val_10 = _mm_load_ps(h1Ptr0); h1Ptr0+=4;
h00 = _mm_shuffle_ps(h0Val_0, h0Val_1, _MM_SHUFFLE(1, 0, 1, 0));
h01 = _mm_shuffle_ps(h0Val_0, h0Val_1, _MM_SHUFFLE(3, 2, 3, 2));
if (nof_rxant == 2) {
h0Val_01 = _mm_load_ps(h0Ptr1); h0Ptr1+=4; h0Val_11 = _mm_load_ps(h0Ptr1); h0Ptr1+=4;
h1Val_01 = _mm_load_ps(h1Ptr1); h1Ptr1+=4; h1Val_11 = _mm_load_ps(h1Ptr1); h1Ptr1+=4;
}
h10 = _mm_shuffle_ps(h1Val_0, h1Val_1, _MM_SHUFFLE(1, 0, 1, 0));
h11 = _mm_shuffle_ps(h1Val_0, h1Val_1, _MM_SHUFFLE(3, 2, 3, 2));
h000 = _mm_shuffle_ps(h0Val_00, h0Val_10, _MM_SHUFFLE(1, 0, 1, 0));
h010 = _mm_shuffle_ps(h0Val_00, h0Val_10, _MM_SHUFFLE(3, 2, 3, 2));
h100 = _mm_shuffle_ps(h1Val_00, h1Val_10, _MM_SHUFFLE(1, 0, 1, 0));
h110 = _mm_shuffle_ps(h1Val_00, h1Val_10, _MM_SHUFFLE(3, 2, 3, 2));
r0Val = _mm_load_ps(yPtr); yPtr+=4;
r1Val = _mm_load_ps(yPtr); yPtr+=4;
r0 = _mm_shuffle_ps(r0Val, r1Val, _MM_SHUFFLE(1, 0, 1, 0));
r1 = _mm_shuffle_ps(r0Val, r1Val, _MM_SHUFFLE(3, 2, 3, 2));
if (nof_rxant == 2) {
h001 = _mm_shuffle_ps(h0Val_01, h0Val_11, _MM_SHUFFLE(1, 0, 1, 0));
h011 = _mm_shuffle_ps(h0Val_01, h0Val_11, _MM_SHUFFLE(3, 2, 3, 2));
h101 = _mm_shuffle_ps(h1Val_01, h1Val_11, _MM_SHUFFLE(1, 0, 1, 0));
h111 = _mm_shuffle_ps(h1Val_01, h1Val_11, _MM_SHUFFLE(3, 2, 3, 2));
}
r0Val0 = _mm_load_ps(yPtr0); yPtr0+=4;
r1Val0 = _mm_load_ps(yPtr0); yPtr0+=4;
r00 = _mm_shuffle_ps(r0Val0, r1Val0, _MM_SHUFFLE(1, 0, 1, 0));
r10 = _mm_shuffle_ps(r0Val0, r1Val0, _MM_SHUFFLE(3, 2, 3, 2));
if (nof_rxant == 2) {
r0Val1 = _mm_load_ps(yPtr1); yPtr1+=4;
r1Val1 = _mm_load_ps(yPtr1); yPtr1+=4;
r01 = _mm_shuffle_ps(r0Val1, r1Val1, _MM_SHUFFLE(1, 0, 1, 0));
r11 = _mm_shuffle_ps(r0Val1, r1Val1, _MM_SHUFFLE(3, 2, 3, 2));
}
/* Compute channel gain */
hhadd = _mm_hadd_ps(_mm_mul_ps(h00, h00), _mm_mul_ps(h11, h11));
hhadd = _mm_hadd_ps(_mm_mul_ps(h000, h000), _mm_mul_ps(h110, h110));
hhshuf = _mm_shuffle_ps(hhadd, hhadd, _MM_SHUFFLE(3, 1, 2, 0));
hhsum = _mm_hadd_ps(hhshuf, hhshuf);
hh = _mm_shuffle_ps(hhsum, hhsum, _MM_SHUFFLE(1, 1, 0, 0)); // h00^2+h11^2
/* Add channel from 2nd antenna */
if (nof_rxant == 2) {
hhadd = _mm_hadd_ps(_mm_mul_ps(h001, h001), _mm_mul_ps(h111, h111));
hhshuf = _mm_shuffle_ps(hhadd, hhadd, _MM_SHUFFLE(3, 1, 2, 0));
hhsum = _mm_hadd_ps(hhshuf, hhshuf);
hh = _mm_add_ps(hh, _mm_shuffle_ps(hhsum, hhsum, _MM_SHUFFLE(1, 1, 0, 0))); // h00^2+h11^2
}
// Conjugate value
h00conj = _mm_xor_ps(h00, conjugator);
h01conj = _mm_xor_ps(h01, conjugator);
r0conj = _mm_xor_ps(r0, conjugator);
r1conj = _mm_xor_ps(r1, conjugator);
h00conj0 = _mm_xor_ps(h000, conjugator);
h01conj0 = _mm_xor_ps(h010, conjugator);
r0conj0 = _mm_xor_ps(r00, conjugator);
r1conj0 = _mm_xor_ps(r10, conjugator);
if (nof_rxant == 2) {
h00conj1 = _mm_xor_ps(h001, conjugator);
h01conj1 = _mm_xor_ps(h011, conjugator);
r0conj1 = _mm_xor_ps(r01, conjugator);
r1conj1 = _mm_xor_ps(r11, conjugator);
}
// Multiply by channel matrix
x0 = _mm_add_ps(PROD(h00conj, r0), PROD(h11, r1conj));
x1 = _mm_sub_ps(PROD(h01conj, r1), PROD(h10, r0conj));
x0 = _mm_add_ps(PROD(h00conj0, r00), PROD(h110, r1conj0));
x1 = _mm_sub_ps(PROD(h01conj0, r10), PROD(h100, r0conj0));
// Add received symbol from 2nd antenna
if (nof_rxant == 2) {
x0 = _mm_add_ps(x0, _mm_add_ps(PROD(h00conj1, r01), PROD(h111, r1conj1)));
x1 = _mm_add_ps(x1, _mm_sub_ps(PROD(h01conj1, r11), PROD(h101, r0conj1)));
}
x0 = _mm_mul_ps(_mm_div_ps(x0, hh), sqrt2);
x1 = _mm_mul_ps(_mm_div_ps(x1, hh), sqrt2);
_mm_store_ps(x0Ptr, x0); x0Ptr+=4;
_mm_store_ps(x1Ptr, x1); x1Ptr+=4;
}
// Compute remaining symbols using generic implementation
srslte_predecoding_diversity_gen_(y, h, x, 2, nof_symbols, 4*(nof_symbols/4));
srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, 2, nof_symbols, 4*(nof_symbols/4));
return nof_symbols;
}
#endif
int srslte_predecoding_diversity(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_symbols)
{
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS];
uint32_t nof_rxant = 1;
for (int i=0;i<nof_ports;i++) {
h[i][0] = h_[i];
}
y[0] = y_;
#ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_ports == 2) {
return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols);
} else {
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols);
}
#else
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols);
#endif
}
int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols)
{
#ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_ports == 2) {
return srslte_predecoding_diversity2_sse(y, h, x, nof_symbols);
return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols);
} else {
return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols);
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols);
}
#else
return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols);
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols);
#endif
}
/* 36.211 v10.3.0 Section 6.3.4 */
int srslte_predecoding_type(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) {
@ -341,6 +532,9 @@ int srslte_predecoding_type(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_M
}
switch (type) {
case SRSLTE_MIMO_TYPE_CDD:
fprintf(stderr, "CCD not supported\n");
return -1;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) {
return srslte_predecoding_single(y, h[0], x[0], nof_symbols, noise_estimate);
@ -442,6 +636,9 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
}
switch (type) {
case SRSLTE_MIMO_TYPE_CDD:
fprintf(stderr, "CCD not supported\n");
return -1;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) {
return srslte_precoding_single(x[0], y[0], nof_symbols);

View File

@ -53,13 +53,12 @@ add_test(layermap_multiplex_28 layermap_test -n 1000 -m multiplex -c 2 -l 8)
# LAYER MAPPING TEST
########################################################################
add_executable(precoding_test precoding_test.c)
add_executable(precoding_test precoder_test.c)
target_link_libraries(precoding_test srslte)
add_test(precoding_single precoding_test -n 1000 -m single)
add_test(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2)
add_test(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4)

View File

@ -0,0 +1,128 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* 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.
*
* srsLTE is distributed in the hope that it will be useful,
* 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.
*
* 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/.
*
*/
#include <string.h>
#include "srslte/srslte.h"
#include "srslte/mex/mexutils.h"
/** MEX function to be called from MATLAB to test the predecoder
*/
#define INPUT prhs[0]
#define NLAYERS prhs[1]
#define NPORTS prhs[2]
#define TXSCHEME prhs[3]
#define NOF_INPUTS 3
void help()
{
mexErrMsgTxt
("[output] = srslte_decoder(input, NLayers, NCellRefP, TxScheme)\n\n");
}
/* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
cf_t *input = NULL;
cf_t *output = NULL;
if (nrhs < NOF_INPUTS) {
help();
return;
}
// Read input symbols
int nof_symbols = mexutils_read_cf(INPUT, &input);
if (nof_symbols < 0) {
mexErrMsgTxt("Error reading input\n");
return;
}
uint32_t nof_layers = mxGetScalar(NLAYERS);
uint32_t nof_tx_ports = mxGetScalar(NPORTS);
uint32_t nof_codewords = 1;
mexPrintf("nof_tx_ports=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_layers, nof_symbols);
cf_t *y[SRSLTE_MAX_PORTS];
cf_t *x[SRSLTE_MAX_LAYERS];
cf_t *d[SRSLTE_MAX_CODEWORDS];
d[0] = input; // Single codeword supported only
/* Allocate memory */
for (int i = 0; i < nof_layers; i++) {
x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols/nof_layers);
}
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports/nof_layers);
for (int i=0;i<nof_tx_ports;i++) {
y[i] = &output[i*nof_symbols/nof_layers];
}
char *txscheme = "Port0";
if (nrhs >= NOF_INPUTS) {
txscheme = mxArrayToString(TXSCHEME);
}
srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
if (!strcmp(txscheme, "Port0")) {
type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
} else if (!strcmp(txscheme, "TxDiversity")) {
type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (!strcmp(txscheme, "CDD")) {
type = SRSLTE_MIMO_TYPE_CDD;
} else if (!strcmp(txscheme, "SpatialMux")) {
type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
} else {
mexPrintf("Unsupported TxScheme=%s\n", txscheme);
return;
}
int symbols_layers[SRSLTE_MAX_LAYERS];
for (int i=0;i<nof_layers;i++) {
symbols_layers[i] = nof_symbols/nof_layers;
}
srslte_layermap_type(d, x, nof_codewords, nof_layers, symbols_layers, type);
srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols/nof_layers, type);
if (nlhs >= 1) {
mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports);
}
if (input) {
free(input);
}
if (output) {
free(output);
}
for (int i=0;i<nof_layers;i++) {
if (x[i]) {
free(x[i]);
}
}
return;
}

View File

@ -33,6 +33,7 @@
#define INPUT prhs[0]
#define HEST prhs[1]
#define NEST prhs[2]
#define NOF_INPUTS 2
@ -56,44 +57,73 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
// Read input symbols
nof_symbols = mexutils_read_cf(INPUT, &input);
if (nof_symbols < 0) {
if (mexutils_read_cf(INPUT, &input) < 0) {
mexErrMsgTxt("Error reading input\n");
return;
}
uint32_t nof_tx_ports = 1;
uint32_t nof_rx_ants = 1;
const mwSize *dims = mxGetDimensions(INPUT);
mwSize ndims = mxGetNumberOfDimensions(INPUT);
nof_symbols = dims[0];
if (ndims >= 2) {
nof_rx_ants = dims[1];
}
// Read channel estimates
uint32_t nof_symbols2 = mexutils_read_cf(HEST, &hest);
if (nof_symbols < 0) {
if (mexutils_read_cf(HEST, &hest) < 0) {
mexErrMsgTxt("Error reading hest\n");
return;
}
if ((nof_symbols2 % nof_symbols) != 0) {
mexErrMsgTxt("Hest size must be multiple of input size\n");
return;
dims = mxGetDimensions(HEST);
ndims = mxGetNumberOfDimensions(HEST);
if (ndims == 3) {
nof_tx_ports = dims[2];
}
// Calculate number of ports
uint32_t nof_ports = nof_symbols2/nof_symbols;
cf_t *x[8];
cf_t *h[4];
mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_symbols=%d\n", nof_tx_ports, nof_rx_ants, nof_symbols);
// Read noise estimate
float noise_estimate = 0;
if (nrhs >= NOF_INPUTS) {
noise_estimate = mxGetScalar(NEST);
}
cf_t *x[SRSLTE_MAX_LAYERS];
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
x[i] = NULL;
}
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
for (int j=0;j<SRSLTE_MAX_PORTS;j++) {
h[i][j] = NULL;
}
}
/* Allocate memory */
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols);
int i;
for (i = 0; i < nof_ports; i++) {
for (int i = 0; i < nof_tx_ports; i++) {
x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols);
h[i] = &hest[i*nof_symbols];
}
for (;i<8;i++) {
x[i] = NULL;
}
for (i=nof_ports;i<4;i++) {
h[i] = NULL;
for (int j=0;j<nof_rx_ants;j++) {
h[i][j] = &hest[i*nof_symbols*nof_rx_ants + j*nof_symbols];
}
}
for (int j=0;j<nof_rx_ants;j++) {
y[j] = &input[j*nof_symbols];
}
if (nof_tx_ports > 1) {
srslte_predecoding_diversity_multi(y, h, x, nof_rx_ants, nof_tx_ports, nof_symbols);
srslte_layerdemap_diversity(x, output, nof_tx_ports, nof_symbols / nof_tx_ports);
} else {
srslte_predecoding_single_multi(y, h[0], output, nof_rx_ants, nof_symbols, noise_estimate);
}
srslte_predecoding_diversity(input, h, x, nof_ports, nof_symbols);
srslte_layerdemap_diversity(x, output, nof_ports, nof_symbols / nof_ports);
if (nlhs >= 1) {
mexutils_write_cf(output, &plhs[0], nof_symbols, 1);
@ -105,7 +135,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
if (output) {
free(output);
}
for (i=0;i<8;i++) {
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
if (x[i]) {
free(x[i]);
}

View File

@ -57,10 +57,14 @@ bool srslte_pcfich_exists(int nframe, int nslot) {
return true;
}
int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell) {
return srslte_pcfich_init_multi(q, regs, cell, 1);
}
/** Initializes the pcfich channel receiver.
* On error, returns -1 and frees the structrure
*/
int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell) {
int srslte_pcfich_init_multi(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
@ -73,6 +77,7 @@ int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t ce
q->cell = cell;
q->regs = regs;
q->nof_symbols = PCFICH_RE;
q->nof_rx_antennas = nof_rx_antennas;
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
goto clean;
@ -145,21 +150,33 @@ int srslte_pcfich_cfi_encode(uint32_t cfi, uint8_t bits[PCFICH_CFI_LEN]) {
}
}
int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t nsubframe, uint32_t *cfi, float *corr_result)
{
cf_t *_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
_sf_symbols[0] = sf_symbols;
for (int i=0;i<q->cell.nof_ports;i++) {
_ce[i][0] = ce[i];
}
return srslte_pcfich_decode_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi, corr_result);
}
/* Decodes the PCFICH channel and saves the CFI in the cfi pointer.
*
* Returns 1 if successfully decoded the CFI, 0 if not and -1 on error
*/
int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t nsubframe, uint32_t *cfi, float *corr_result)
int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t nsubframe, uint32_t *cfi, float *corr_result)
{
/* Set pointers for layermapping & precoding */
int i;
cf_t *x[SRSLTE_MAX_LAYERS];
cf_t *ce_precoding[SRSLTE_MAX_PORTS];
if (q != NULL &&
slot_symbols != NULL &&
sf_symbols != NULL &&
nsubframe < SRSLTE_NSUBFRAMES_X_FRAME)
{
@ -167,34 +184,37 @@ int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
x[i] = q->x[i];
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
ce_precoding[i] = q->ce[i];
}
cf_t *q_symbols[SRSLTE_MAX_PORTS];
cf_t *q_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
/* extract symbols */
if (q->nof_symbols
!= srslte_regs_pcfich_get(q->regs, slot_symbols, q->symbols[0])) {
fprintf(stderr, "There was an error getting the PCFICH symbols\n");
return SRSLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i], q->ce[i])) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->nof_symbols
!= srslte_regs_pcfich_get(q->regs, sf_symbols[j], q->symbols[j])) {
fprintf(stderr, "There was an error getting the PCFICH symbols\n");
return SRSLTE_ERROR;
}
}
q_symbols[j] = q->symbols[j];
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i][j], q->ce[i][j])) {
fprintf(stderr, "There was an error getting the PCFICH symbols\n");
return SRSLTE_ERROR;
}
q_ce[i][j] = q->ce[i][j];
}
}
/* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate);
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, noise_estimate);
} else {
srslte_predecoding_diversity(q->symbols[0], ce_precoding, x,
q->cell.nof_ports, q->nof_symbols);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports);
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);
}
/* demodulate symbols */
@ -229,14 +249,14 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR
/* Set pointers for layermapping & precoding */
cf_t *x[SRSLTE_MAX_LAYERS];
cf_t *symbols_precoding[SRSLTE_MAX_PORTS];
cf_t *q_symbols[SRSLTE_MAX_PORTS];
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->x[i];
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
symbols_precoding[i] = q->symbols[i];
q_symbols[i] = q->symbols[i];
}
/* pack CFI */
@ -250,8 +270,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR
/* layer mapping & precoding */
if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports);
srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);
} else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));
}

View File

@ -62,8 +62,12 @@ float srslte_pdcch_coderate(uint32_t nof_bits, uint32_t l) {
/** Initializes the PDCCH transmitter and receiver */
int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) {
return srslte_pdcch_init_multi(q, regs, cell, 1);
}
int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t i;
if (q != NULL &&
regs != NULL &&
@ -73,6 +77,7 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell
bzero(q, sizeof(srslte_pdcch_t));
q->cell = cell;
q->regs = regs;
q->nof_rx_antennas = nof_rx_antennas;
/* Allocate memory for the maximum number of PDCCH bits (CFI=3) */
q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72;
@ -87,7 +92,7 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell
goto clean;
}
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
// we need to pregenerate the sequence for the maximum number of bits, which is 8 times
// the maximum number of REGs (for CFI=3)
if (srslte_sequence_pdcch(&q->seq[i], 2 * i, q->cell.id, 8*srslte_regs_pdcch_nregs(q->regs, 3))) {
@ -117,17 +122,21 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell
goto clean;
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->ce[i]) {
goto clean;
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j=0;j<q->nof_rx_antennas;j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->ce[i][j]) {
goto clean;
}
}
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->x[i]) {
goto clean;
}
q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->symbols[i]) {
}
for (int j=0;j<q->nof_rx_antennas;j++) {
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->symbols[j]) {
goto clean;
}
}
@ -142,7 +151,6 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell
}
void srslte_pdcch_free(srslte_pdcch_t *q) {
int i;
if (q->e) {
free(q->e);
@ -153,19 +161,22 @@ void srslte_pdcch_free(srslte_pdcch_t *q) {
if (q->d) {
free(q->d);
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (q->ce[i]) {
free(q->ce[i]);
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
if (q->x[i]) {
free(q->x[i]);
}
if (q->symbols[i]) {
free(q->symbols[i]);
}
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->symbols[j]) {
free(q->symbols[j]);
}
}
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
srslte_sequence_free(&q->seq[i]);
}
@ -379,13 +390,27 @@ int srslte_pdcch_decode_msg(srslte_pdcch_t *q,
int cnt=0;
int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t nsubframe, uint32_t cfi)
{
cf_t *_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
_sf_symbols[0] = sf_symbols;
for (int i=0;i<q->cell.nof_ports;i++) {
_ce[i][0] = ce[i];
}
return srslte_pdcch_extract_llr_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi);
}
/** Extracts the LLRs from srslte_dci_location_t location of the subframe and stores them in the srslte_pdcch_t structure.
* DCI messages can be extracted from this location calling the function srslte_pdcch_decode_msg().
* Every time this function is called (with a different location), the last demodulated symbols are overwritten and
* new messages from other locations can be decoded
*/
int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t nsubframe, uint32_t cfi) {
int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t nsubframe, uint32_t cfi)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -415,27 +440,29 @@ int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLT
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
/* extract symbols */
int n = srslte_regs_pdcch_get(q->regs, sf_symbols, q->symbols[0]);
if (nof_symbols != n) {
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
return ret;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = srslte_regs_pdcch_get(q->regs, ce[i], q->ce[i]);
for (int j=0;j<q->nof_rx_antennas;j++) {
int n = srslte_regs_pdcch_get(q->regs, sf_symbols[j], q->symbols[j]);
if (nof_symbols != n) {
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
return ret;
}
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = srslte_regs_pdcch_get(q->regs, ce[i][j], q->ce[i][j]);
if (nof_symbols != n) {
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
return ret;
}
}
}
/* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, nof_symbols, noise_estimate/2);
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, noise_estimate/2);
} else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols);
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
}

View File

@ -202,13 +202,20 @@ int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols,
return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false);
}
int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell)
{
return srslte_pdsch_init_multi(q, cell, 1);
}
/** Initializes the PDCCH transmitter and receiver */
int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) {
int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
int i;
if (q != NULL &&
srslte_cell_isvalid(&cell))
if (q != NULL &&
srslte_cell_isvalid(&cell) &&
nof_rx_antennas <= SRSLTE_MAX_PORTS)
{
bzero(q, sizeof(srslte_pdsch_t));
@ -216,7 +223,8 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) {
q->cell = cell;
q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp);
q->nof_rx_antennas = nof_rx_antennas;
INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
q->cell.nof_prb, q->max_re);
@ -241,19 +249,23 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) {
}
for (i = 0; i < q->cell.nof_ports; i++) {
q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->ce[i]) {
goto clean;
}
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->x[i]) {
goto clean;
}
q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->symbols[i]) {
goto clean;
for (int j=0;j<q->nof_rx_antennas;j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->ce[i][j]) {
goto clean;
}
}
}
for (int j=0;j<q->nof_rx_antennas;j++) {
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->symbols[j]) {
goto clean;
}
}
q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI);
if (!q->users) {
@ -280,17 +292,20 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
free(q->d);
}
for (i = 0; i < q->cell.nof_ports; i++) {
if (q->ce[i]) {
free(q->ce[i]);
}
if (q->x[i]) {
free(q->x[i]);
}
if (q->symbols[i]) {
free(q->symbols[i]);
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
}
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->symbols[j]) {
free(q->symbols[j]);
}
}
if (q->users) {
for (uint16_t u=0;u<SRSLTE_SIRNTI;u++) {
if (q->users[u]) {
@ -363,13 +378,28 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
}
}
/** Decodes the PDSCH from the received symbols
*/
int srslte_pdsch_decode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint16_t rnti, uint8_t *data)
{
cf_t *_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
_sf_symbols[0] = sf_symbols;
for (int i=0;i<q->cell.nof_ports;i++) {
_ce[i][0] = ce[i];
}
return srslte_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, data);
}
/** Decodes the PDSCH from the received symbols
*/
int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate,
uint16_t rnti, uint8_t *data)
{
/* Set pointers for layermapping & precoding */
uint32_t i, n;
@ -391,31 +421,31 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
/* extract symbols */
n = srslte_pdsch_get(q, sf_symbols, q->symbols[0], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
if (n != cfg->nbits.nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n);
return SRSLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = srslte_pdsch_get(q, ce[i], q->ce[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
for (int j=0;j<q->nof_rx_antennas;j++) {
/* extract symbols */
n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
if (n != cfg->nbits.nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n);
return SRSLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
if (n != cfg->nbits.nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n);
return SRSLTE_ERROR;
}
}
}
/* TODO: only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, cfg->nbits.nof_re, noise_estimate);
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate);
} else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports,
cfg->nbits.nof_re);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports,
cfg->nbits.nof_re / q->cell.nof_ports);
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nbits.nof_re);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports);
}
if (SRSLTE_VERBOSE_ISDEBUG()) {

View File

@ -67,8 +67,14 @@ void srslte_phich_reset(srslte_phich_t *q, cf_t *slot_symbols[SRSLTE_MAX_PORTS])
}
}
int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell)
{
return srslte_phich_init_multi(q, regs, cell, 1);
}
/** Initializes the phich channel receiver */
int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) {
int srslte_phich_init_multi(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
@ -81,6 +87,7 @@ int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell
q->cell = cell;
q->regs = regs;
q->nof_rx_antennas = nof_rx_antennas;
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) {
goto clean;
@ -155,19 +162,32 @@ void srslte_phich_ack_encode(uint8_t ack, uint8_t bits[SRSLTE_PHICH_NBITS]) {
memset(bits, ack, 3 * sizeof(uint8_t));
}
int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance)
{
cf_t *_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
_sf_symbols[0] = sf_symbols;
for (int i=0;i<q->cell.nof_ports;i++) {
_ce[i][0] = ce[i];
}
return srslte_phich_decode_multi(q, _sf_symbols, _ce, noise_estimate, ngroup, nseq, subframe, ack, distance);
}
/* Decodes the phich channel and saves the CFI in the cfi pointer.
*
* Returns 1 if successfully decoded the CFI, 0 if not and -1 on error
*/
int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) {
int srslte_phich_decode_multi(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate,
uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance)
{
/* Set pointers for layermapping & precoding */
int i, j;
cf_t *x[SRSLTE_MAX_LAYERS];
cf_t *ce_precoding[SRSLTE_MAX_PORTS];
if (q == NULL || slot_symbols == NULL) {
if (q == NULL || sf_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
@ -198,34 +218,37 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_M
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
x[i] = q->x[i];
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
ce_precoding[i] = q->ce[i];
}
cf_t *q_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *q_sf_symbols[SRSLTE_MAX_PORTS];
/* extract symbols */
if (SRSLTE_PHICH_MAX_NSYMB
!= srslte_regs_phich_get(q->regs, slot_symbols, q->symbols[0], ngroup)) {
fprintf(stderr, "There was an error getting the phich symbols\n");
return SRSLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (SRSLTE_PHICH_MAX_NSYMB
!= srslte_regs_phich_get(q->regs, sf_symbols[j], q->sf_symbols[j], ngroup)) {
fprintf(stderr, "There was an error getting the phich symbols\n");
return SRSLTE_ERROR;
}
q_sf_symbols[j] = q->sf_symbols[j];
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i][j], q->ce[i][j], ngroup)) {
fprintf(stderr, "There was an error getting the phich symbols\n");
return SRSLTE_ERROR;
}
q_ce[i][j] = q->ce[i][j];
}
}
/* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d0, SRSLTE_PHICH_MAX_NSYMB, noise_estimate);
srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, noise_estimate);
} else {
srslte_predecoding_diversity(q->symbols[0], ce_precoding, x,
q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB);
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports,
SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB);
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
}
DEBUG("Recv!!: \n", 0);
DEBUG("d0: ", 0);
@ -328,7 +351,7 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_
x[i] = q->x[i];
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
symbols_precoding[i] = q->symbols[i];
symbols_precoding[i] = q->sf_symbols[i];
}
/* encode ACK/NACK bit */
@ -391,12 +414,12 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_
SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
/**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */
} else {
memcpy(q->symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t));
memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t));
}
/* mapping to resource elements */
for (i = 0; i < q->cell.nof_ports; i++) {
if (srslte_regs_phich_add(q->regs, q->symbols[i], ngroup, slot_symbols[i])
if (srslte_regs_phich_add(q->regs, q->sf_symbols[i], ngroup, slot_symbols[i])
< 0) {
fprintf(stderr, "Error putting PCHICH resource elements\n");
return SRSLTE_ERROR;

View File

@ -137,7 +137,7 @@ int base_init() {
exit(-1);
}
if (srslte_ue_dl_init(&ue_dl, cell)) {
if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) {
fprintf(stderr, "Error initializing UE DL\n");
return -1;
}

View File

@ -55,7 +55,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_ofdm_t ofdm_rx;
srslte_pdsch_t pdsch;
srslte_chest_dl_t chest;
cf_t *input_fft;
cf_t *input_fft[SRSLTE_MAX_PORTS];
srslte_pdsch_cfg_t cfg;
srslte_softbuffer_rx_t softbuffer;
uint32_t rnti32;
@ -92,8 +92,16 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
fprintf(stderr, "Error initializing FFT\n");
return;
}
if (srslte_pdsch_init(&pdsch, cell)) {
const size_t ndims = mxGetNumberOfDimensions(INPUT);
uint32_t nof_antennas = 1;
if (ndims >= 3) {
const mwSize *dims = mxGetDimensions(INPUT);
nof_antennas = dims[2];
}
if (srslte_pdsch_init_multi(&pdsch, cell, nof_antennas)) {
mexErrMsgTxt("Error initiating PDSCH\n");
return;
}
@ -188,18 +196,19 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
nof_retx = mexutils_getLength(INPUT);
}
cf_t *ce[SRSLTE_MAX_PORTS];
for (i=0;i<cell.nof_ports;i++) {
ce[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
for (int j=0;j<SRSLTE_MAX_PORTS;j++) {
for (i=0;i<cell.nof_ports;i++) {
ce[i][j] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
}
}
uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8);
if (!data_bytes) {
return;
}
srslte_sch_set_max_noi(&pdsch.dl_sch, max_iterations);
input_fft = NULL;
bool input_fft_allocated = false;
int r=-1;
for (int rvIdx=0;rvIdx<nof_retx && r != 0;rvIdx++) {
@ -218,11 +227,17 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexErrMsgTxt("Error reading input signal\n");
return;
}
if (insignal_len == SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)) {
input_fft = input_signal;
} else {
input_fft = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
srslte_ofdm_rx_sf(&ofdm_rx, input_signal, input_fft);
if (!(insignal_len % SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) {
for (int i=0;i<nof_antennas;i++) {
input_fft[i] = &input_signal[i*insignal_len/nof_antennas];
}
} else if (!(insignal_len % SRSLTE_SF_LEN_PRB(cell.nof_prb))) {
for (int i=0;i<nof_antennas;i++) {
input_fft[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
srslte_ofdm_rx_sf(&ofdm_rx, &input_signal[i*insignal_len/nof_antennas], input_fft[i]);
input_fft_allocated = true;
}
free(input_signal);
}
@ -230,16 +245,18 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
cf_t *cearray = NULL;
mexutils_read_cf(prhs[NOF_INPUTS], &cearray);
cf_t *cearray_ptr = cearray;
for (i=0;i<cell.nof_ports;i++) {
for (int j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
ce[i][j] = *cearray_ptr;
cearray_ptr++;
}
}
for (int k=0;k<nof_antennas;k++) {
for (i=0;i<cell.nof_ports;i++) {
for (int j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
ce[i][k][j] = *cearray_ptr;
cearray_ptr++;
}
}
}
if (cearray)
free(cearray);
} else {
srslte_chest_dl_estimate(&chest, input_fft, ce, cfg.sf_idx);
srslte_chest_dl_estimate_multi(&chest, input_fft, ce, cfg.sf_idx, nof_antennas);
}
float noise_power;
@ -251,7 +268,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
noise_power = srslte_chest_dl_get_noise_estimate(&chest);
}
r = srslte_pdsch_decode(&pdsch, &cfg, &softbuffer, input_fft, ce, noise_power, rnti, data_bytes);
r = srslte_pdsch_decode_multi(&pdsch, &cfg, &softbuffer, input_fft, ce, noise_power, rnti, data_bytes);
}
uint8_t *data = malloc(grant.mcs.tbs);
@ -273,21 +290,41 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexutils_write_s(pdsch.e, &plhs[4], cfg.nbits.nof_bits, 1);
}
if (nlhs >= 6) {
mexutils_write_cf(ce[0], &plhs[5], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1);
uint32_t len = nof_antennas*cell.nof_ports*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);
cf_t *cearray_ptr = srslte_vec_malloc(len*sizeof(cf_t));
int n=0;
for (i=0;i<cell.nof_ports;i++) {
for (int k=0;k<nof_antennas;k++) {
for (int j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
cearray_ptr[n] = ce[i][k][j];
n++;
}
}
}
mexutils_write_cf(cearray_ptr, &plhs[5], len, 1);
if (cearray_ptr) {
free(cearray_ptr);
}
}
srslte_softbuffer_rx_free(&softbuffer);
srslte_chest_dl_free(&chest);
srslte_pdsch_free(&pdsch);
srslte_ofdm_rx_free(&ofdm_rx);
for (i=0;i<cell.nof_ports;i++) {
free(ce[i]);
for (int j=0;j<nof_antennas;j++) {
for (i=0;i<cell.nof_ports;i++) {
if (ce[i][j]) {
free(ce[i][j]);
}
}
if (input_fft_allocated) {
if (input_fft[j]) {
free(input_fft[j]);
}
}
}
free(data_bytes);
free(data);
if (input_fft) {
free(input_fft);
}
return;
}

View File

@ -178,6 +178,11 @@ float rf_blade_get_rssi(void *h)
return 0;
}
int rf_blade_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
{
return rf_blade_open(args, h);
}
int rf_blade_open(char *args, void **h)
{
*h = NULL;
@ -413,6 +418,17 @@ void rf_blade_get_time(void *h, time_t *secs, double *frac_secs)
timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs);
}
int rf_blade_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
{
return rf_blade_recv_with_time(h, *data, nsamples, blocking, secs, frac_secs);
}
int rf_blade_recv_with_time(void *h,
void *data,
uint32_t nsamples,

View File

@ -33,6 +33,8 @@
SRSLTE_API int rf_blade_open(char *args,
void **handler);
SRSLTE_API int rf_blade_open_multi(char *args,
void **handler, uint32_t nof_rx_antennas);
SRSLTE_API char* rf_blade_devname(void *h);
@ -82,6 +84,13 @@ SRSLTE_API void rf_blade_register_error_handler(void *h,
SRSLTE_API double rf_blade_set_rx_freq(void *h,
double freq);
SRSLTE_API int rf_blade_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
SRSLTE_API int rf_blade_recv_with_time(void *h,
void *data,
uint32_t nsamples,

View File

@ -38,6 +38,7 @@ typedef struct {
void (*srslte_rf_suppress_stdout)(void *h);
void (*srslte_rf_register_error_handler)(void *h, srslte_rf_error_handler_t error_handler);
int (*srslte_rf_open)(char *args, void **h);
int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_rx_antennas);
int (*srslte_rf_close)(void *h);
void (*srslte_rf_set_master_clock_rate)(void *h, double rate);
bool (*srslte_rf_is_master_clock_dynamic)(void *h);
@ -52,6 +53,8 @@ typedef struct {
void (*srslte_rf_get_time)(void *h, time_t *secs, double *frac_secs);
int (*srslte_rf_recv_with_time)(void *h, void *data, uint32_t nsamples,
bool blocking, time_t *secs,double *frac_secs);
int (*srslte_rf_recv_with_time_multi)(void *h, void **data, uint32_t nsamples,
bool blocking, time_t *secs,double *frac_secs);
int (*srslte_rf_send_timed)(void *h, void *data, int nsamples,
time_t secs, double frac_secs, bool has_time_spec,
bool blocking, bool is_start_of_burst, bool is_end_of_burst);
@ -78,6 +81,7 @@ static rf_dev_t dev_uhd = {
rf_uhd_suppress_stdout,
rf_uhd_register_error_handler,
rf_uhd_open,
rf_uhd_open_multi,
rf_uhd_close,
rf_uhd_set_master_clock_rate,
rf_uhd_is_master_clock_dynamic,
@ -91,6 +95,7 @@ static rf_dev_t dev_uhd = {
rf_uhd_set_tx_freq,
rf_uhd_get_time,
rf_uhd_recv_with_time,
rf_uhd_recv_with_time_multi,
rf_uhd_send_timed,
rf_uhd_set_tx_cal,
rf_uhd_set_rx_cal
@ -114,6 +119,7 @@ static rf_dev_t dev_blade = {
rf_blade_suppress_stdout,
rf_blade_register_error_handler,
rf_blade_open,
rf_blade_open_multi,
rf_blade_close,
rf_blade_set_master_clock_rate,
rf_blade_is_master_clock_dynamic,
@ -127,6 +133,7 @@ static rf_dev_t dev_blade = {
rf_blade_set_tx_freq,
rf_blade_get_time,
rf_blade_recv_with_time,
rf_blade_recv_with_time_multi,
rf_blade_send_timed,
rf_blade_set_tx_cal,
rf_blade_set_rx_cal

View File

@ -99,6 +99,10 @@ const char* srslte_rf_get_devname(srslte_rf_t *rf) {
}
int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
return srslte_rf_open_devname_multi(rf, devname, args, 1);
}
int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_rx_antennas) {
/* Try to open the device if name is provided */
if (devname) {
if (devname[0] != '\0') {
@ -106,7 +110,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
while(available_devices[i] != NULL) {
if (!strcmp(available_devices[i]->name, devname)) {
rf->dev = available_devices[i];
return available_devices[i]->srslte_rf_open(args, &rf->handler);
return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas);
}
i++;
}
@ -117,7 +121,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
/* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */
int i=0;
while(available_devices[i] != NULL) {
if (!available_devices[i]->srslte_rf_open(args, &rf->handler)) {
if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas)) {
rf->dev = available_devices[i];
return 0;
}
@ -182,7 +186,12 @@ void srslte_rf_register_error_handler(srslte_rf_t *rf, srslte_rf_error_handler_t
int srslte_rf_open(srslte_rf_t *h, char *args)
{
return srslte_rf_open_devname(h, NULL, args);
return srslte_rf_open_devname_multi(h, NULL, args, 1);
}
int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas)
{
return srslte_rf_open_devname_multi(h, NULL, args, nof_rx_antennas);
}
int srslte_rf_close(srslte_rf_t *rf)
@ -231,6 +240,11 @@ int srslte_rf_recv(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking
return srslte_rf_recv_with_time(rf, data, nsamples, blocking, NULL, NULL);
}
int srslte_rf_recv_multi(srslte_rf_t *rf, void **data, uint32_t nsamples, bool blocking)
{
return srslte_rf_recv_with_time_multi(rf, data, nsamples, blocking, NULL, NULL);
}
int srslte_rf_recv_with_time(srslte_rf_t *rf,
void *data,
uint32_t nsamples,
@ -241,6 +255,16 @@ int srslte_rf_recv_with_time(srslte_rf_t *rf,
return ((rf_dev_t*) rf->dev)->srslte_rf_recv_with_time(rf->handler, data, nsamples, blocking, secs, frac_secs);
}
int srslte_rf_recv_with_time_multi(srslte_rf_t *rf,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
{
return ((rf_dev_t*) rf->dev)->srslte_rf_recv_with_time_multi(rf->handler, data, nsamples, blocking, secs, frac_secs);
}
double srslte_rf_set_tx_gain(srslte_rf_t *rf, double gain)
{
return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_gain(rf->handler, gain);

View File

@ -51,6 +51,8 @@ typedef struct {
bool dynamic_rate;
bool has_rssi;
uhd_sensor_value_handle rssi_value;
uint32_t nof_rx_channels;
int nof_tx_channels;
} rf_uhd_handler_t;
void suppress_handler(const char *x)
@ -204,9 +206,11 @@ int rf_uhd_stop_rx_stream(void *h)
void rf_uhd_flush_buffer(void *h)
{
int n;
cf_t tmp[1024];
cf_t tmp1[1024];
cf_t tmp2[1024];
void *data[2] = {tmp1, tmp2};
do {
n = rf_uhd_recv_with_time(h, tmp, 1024, 0, NULL, NULL);
n = rf_uhd_recv_with_time_multi(h, data, 1024, 0, NULL, NULL);
} while (n > 0);
}
@ -238,6 +242,11 @@ float rf_uhd_get_rssi(void *h) {
}
int rf_uhd_open(char *args, void **h)
{
return rf_uhd_open_multi(args, h, 1);
}
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
{
if (h) {
*h = NULL;
@ -318,14 +327,17 @@ int rf_uhd_open(char *args, void **h)
if (!handler->devname) {
handler->devname = "uhd_unknown";
}
size_t channel = 0;
size_t channel[4] = {0, 1, 2, 3};
uhd_stream_args_t stream_args = {
.cpu_format = "fc32",
.otw_format = "sc16",
.args = "",
.channel_list = &channel,
.n_channels = 1
.channel_list = channel,
.n_channels = nof_rx_antennas
};
handler->nof_rx_channels = nof_rx_antennas;
handler->nof_tx_channels = 1;
// Set external clock reference
if (strstr(args, "clock=external")) {
@ -405,7 +417,9 @@ bool rf_uhd_is_master_clock_dynamic(void *h) {
double rf_uhd_set_rx_srate(void *h, double freq)
{
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_usrp_set_rx_rate(handler->usrp, freq, 0);
for (int i=0;i<handler->nof_rx_channels;i++) {
uhd_usrp_set_rx_rate(handler->usrp, freq, i);
}
uhd_usrp_get_rx_rate(handler->usrp, 0, &freq);
return freq;
}
@ -413,7 +427,9 @@ double rf_uhd_set_rx_srate(void *h, double freq)
double rf_uhd_set_tx_srate(void *h, double freq)
{
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_usrp_set_tx_rate(handler->usrp, freq, 0);
for (int i=0;i<handler->nof_tx_channels;i++) {
uhd_usrp_set_tx_rate(handler->usrp, freq, i);
}
uhd_usrp_get_tx_rate(handler->usrp, 0, &freq);
handler->tx_rate = freq;
return freq;
@ -422,7 +438,9 @@ double rf_uhd_set_tx_srate(void *h, double freq)
double rf_uhd_set_rx_gain(void *h, double gain)
{
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_usrp_set_rx_gain(handler->usrp, gain, 0, "");
for (int i=0;i<handler->nof_rx_channels;i++) {
uhd_usrp_set_rx_gain(handler->usrp, gain, i, "");
}
uhd_usrp_get_rx_gain(handler->usrp, 0, "", &gain);
return gain;
}
@ -430,7 +448,9 @@ double rf_uhd_set_rx_gain(void *h, double gain)
double rf_uhd_set_tx_gain(void *h, double gain)
{
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_usrp_set_tx_gain(handler->usrp, gain, 0, "");
for (int i=0;i<handler->nof_tx_channels;i++) {
uhd_usrp_set_tx_gain(handler->usrp, gain, i, "");
}
uhd_usrp_get_tx_gain(handler->usrp, 0, "", &gain);
return gain;
}
@ -460,7 +480,9 @@ double rf_uhd_set_rx_freq(void *h, double freq)
};
uhd_tune_result_t tune_result;
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_usrp_set_rx_freq(handler->usrp, &tune_request, 0, &tune_result);
for (int i=0;i<handler->nof_rx_channels;i++) {
uhd_usrp_set_rx_freq(handler->usrp, &tune_request, i, &tune_result);
}
uhd_usrp_get_rx_freq(handler->usrp, 0, &freq);
return freq;
}
@ -474,7 +496,9 @@ double rf_uhd_set_tx_freq(void *h, double freq)
};
uhd_tune_result_t tune_result;
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_usrp_set_tx_freq(handler->usrp, &tune_request, 0, &tune_result);
for (int i=0;i<handler->nof_tx_channels;i++) {
uhd_usrp_set_tx_freq(handler->usrp, &tune_request, i, &tune_result);
}
uhd_usrp_get_tx_freq(handler->usrp, 0, &freq);
return freq;
}
@ -492,6 +516,19 @@ int rf_uhd_recv_with_time(void *h,
time_t *secs,
double *frac_secs)
{
return rf_uhd_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs);
}
cf_t data1[1024*100];
cf_t data2[1024*100];
int rf_uhd_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
{
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
size_t rxd_samples;
@ -499,18 +536,20 @@ int rf_uhd_recv_with_time(void *h,
int trials = 0;
if (blocking) {
int n = 0;
cf_t *data_c = (cf_t*) data;
do {
size_t rx_samples = handler->rx_nof_samples;
size_t rx_samples = nsamples;
if (rx_samples > nsamples - n) {
rx_samples = nsamples - n;
}
void *buff = (void*) &data_c[n];
void **buffs_ptr = (void**) &buff;
void *buffs_ptr[4];
for (int i=0;i<handler->nof_rx_channels;i++) {
cf_t *data_c = (cf_t*) data[i];
buffs_ptr[i] = &data_c[n];
}
uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr,
rx_samples, md, 5.0, false, &rxd_samples);
rx_samples, md, 1.0, false, &rxd_samples);
if (error) {
fprintf(stderr, "Error receiving from UHD: %d\n", error);
return -1;
@ -520,9 +559,8 @@ int rf_uhd_recv_with_time(void *h,
trials++;
} while (n < nsamples && trials < 100);
} else {
void **buffs_ptr = (void**) &data;
return uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr,
nsamples, md, 0.0, false, &rxd_samples);
return uhd_rx_streamer_recv(handler->rx_stream, data,
nsamples, md, 0.0, false, &rxd_samples);
}
if (secs && frac_secs) {
uhd_rx_metadata_time_spec(handler->rx_md_first, secs, frac_secs);

View File

@ -37,6 +37,10 @@
SRSLTE_API int rf_uhd_open(char *args,
void **handler);
SRSLTE_API int rf_uhd_open_multi(char *args,
void **handler,
uint32_t nof_rx_antennas);
SRSLTE_API char* rf_uhd_devname(void *h);
SRSLTE_API int rf_uhd_close(void *h);
@ -89,6 +93,13 @@ SRSLTE_API int rf_uhd_recv_with_time(void *h,
time_t *secs,
double *frac_secs);
SRSLTE_API int rf_uhd_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
SRSLTE_API double rf_uhd_set_tx_srate(void *h,
double freq);

View File

@ -82,10 +82,13 @@ free_and_exit:
return ret;
}
int srslte_rf_recv_wrapper_cs(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) {
int srslte_rf_recv_wrapper_cs(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv(h, data, nsamples, 1);
void *ptr[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ptr[i] = data[i];
}
return srslte_rf_recv_with_time_multi(h, ptr, nsamples, 1, NULL, NULL);
}
double srslte_rf_set_rx_gain_th_wrapper(void *h, double f) {
@ -95,12 +98,12 @@ double srslte_rf_set_rx_gain_th_wrapper(void *h, double f) {
/** This function is simply a wrapper to the ue_cell_search module for rf devices
* Return 1 if the MIB is decoded, 0 if not or -1 on error.
*/
int rf_mib_decoder(srslte_rf_t *rf, cell_search_cfg_t *config, srslte_cell_t *cell, float *cfo) {
int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t *config, srslte_cell_t *cell, float *cfo) {
int ret = SRSLTE_ERROR;
srslte_ue_mib_sync_t ue_mib;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
if (srslte_ue_mib_sync_init(&ue_mib, cell->id, cell->cp, srslte_rf_recv_wrapper_cs, (void*) rf)) {
if (srslte_ue_mib_sync_init_multi(&ue_mib, cell->id, cell->cp, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) {
fprintf(stderr, "Error initiating srslte_ue_mib_sync\n");
goto clean_exit;
}
@ -151,8 +154,9 @@ clean_exit:
/** This function is simply a wrapper to the ue_cell_search module for rf devices
*/
int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config,
int force_N_id_2, srslte_cell_t *cell, float *cfo)
int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas,
cell_search_cfg_t *config,
int force_N_id_2, srslte_cell_t *cell, float *cfo)
{
int ret = SRSLTE_ERROR;
srslte_ue_cellsearch_t cs;
@ -160,7 +164,7 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config,
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, (void*) rf)) {
if (srslte_ue_cellsearch_init_multi(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) {
fprintf(stderr, "Error initiating UE cell detect\n");
return SRSLTE_ERROR;
}
@ -234,15 +238,15 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config,
* 0 if no cell was found or MIB could not be decoded,
* -1 on error
*/
int rf_search_and_decode_mib(srslte_rf_t *rf, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo)
int rf_search_and_decode_mib(srslte_rf_t *rf, uint32_t nof_rx_antennas, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo)
{
int ret = SRSLTE_ERROR;
printf("Searching for cell...\n");
ret = rf_cell_search(rf, config, force_N_id_2, cell, cfo);
ret = rf_cell_search(rf, nof_rx_antennas, config, force_N_id_2, cell, cfo);
if (ret > 0) {
printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3);
ret = rf_mib_decoder(rf, config, cell, cfo);
ret = rf_mib_decoder(rf, nof_rx_antennas, config, cell, cfo);
if (ret < 0) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id);
return SRSLTE_ERROR;

View File

@ -36,7 +36,8 @@
#include "srslte/utils/vector.h"
int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames,
int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), void *stream_handler)
int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*),
void *stream_handler)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -55,6 +56,65 @@ int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames,
goto clean_exit;
}
q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
q->nof_rx_antennas = 1;
q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames);
if (!q->candidates) {
perror("malloc");
goto clean_exit;
}
q->mode_ntimes = calloc(sizeof(uint32_t), max_frames);
if (!q->mode_ntimes) {
perror("malloc");
goto clean_exit;
}
q->mode_counted = calloc(sizeof(uint8_t), max_frames);
if (!q->mode_counted) {
perror("malloc");
goto clean_exit;
}
q->max_frames = max_frames;
q->nof_valid_frames = max_frames;
ret = SRSLTE_SUCCESS;
}
clean_exit:
if (ret == SRSLTE_ERROR) {
srslte_ue_cellsearch_free(q);
}
return ret;
}
int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_frames,
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void *stream_handler)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
ret = SRSLTE_ERROR;
srslte_cell_t cell;
bzero(q, sizeof(srslte_ue_cellsearch_t));
bzero(&cell, sizeof(srslte_cell_t));
cell.id = SRSLTE_CELL_ID_UNKNOWN;
cell.nof_prb = SRSLTE_CS_NOF_PRB;
if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) {
fprintf(stderr, "Error initiating ue_sync\n");
goto clean_exit;
}
for (int i=0;i<nof_rx_antennas;i++) {
q->sf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
}
q->nof_rx_antennas = nof_rx_antennas;
q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames);
if (!q->candidates) {
perror("malloc");
@ -86,6 +146,11 @@ clean_exit:
void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t * q)
{
for (int i=0;i<q->nof_rx_antennas;i++) {
if (q->sf_buffer[i]) {
free(q->sf_buffer[i]);
}
}
if (q->candidates) {
free(q->candidates);
}
@ -203,7 +268,6 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q,
srslte_ue_cellsearch_result_t *found_cell)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
cf_t *sf_buffer = NULL;
uint32_t nof_detected_frames = 0;
uint32_t nof_scanned_frames = 0;
@ -215,7 +279,7 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q,
srslte_ue_sync_reset(&q->ue_sync);
do {
ret = srslte_ue_sync_get_buffer(&q->ue_sync, &sf_buffer);
ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
break;

View File

@ -44,13 +44,20 @@ const uint32_t nof_ue_formats = 2;
static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
const uint32_t nof_common_formats = 2;
int srslte_ue_dl_init(srslte_ue_dl_t *q,
srslte_cell_t cell)
srslte_cell_t cell)
{
return srslte_ue_dl_init_multi(q, cell, 1);
}
int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
srslte_cell_t cell,
uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
if (q != NULL &&
nof_rx_antennas <= SRSLTE_MAX_PORTS &&
srslte_cell_isvalid(&cell))
{
ret = SRSLTE_ERROR;
@ -62,6 +69,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
q->pkts_total = 0;
q->pending_ul_dci_rnti = 0;
q->sample_offset = 0;
q->nof_rx_antennas = nof_rx_antennas;
if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n");
@ -75,7 +83,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
fprintf(stderr, "Error initiating REGs\n");
goto clean_exit;
}
if (srslte_pcfich_init(&q->pcfich, &q->regs, q->cell)) {
if (srslte_pcfich_init_multi(&q->pcfich, &q->regs, q->cell, nof_rx_antennas)) {
fprintf(stderr, "Error creating PCFICH object\n");
goto clean_exit;
}
@ -84,12 +92,12 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
goto clean_exit;
}
if (srslte_pdcch_init(&q->pdcch, &q->regs, q->cell)) {
if (srslte_pdcch_init_multi(&q->pdcch, &q->regs, q->cell, nof_rx_antennas)) {
fprintf(stderr, "Error creating PDCCH object\n");
goto clean_exit;
}
if (srslte_pdsch_init(&q->pdsch, q->cell)) {
if (srslte_pdsch_init_multi(&q->pdsch, q->cell, nof_rx_antennas)) {
fprintf(stderr, "Error creating PDSCH object\n");
goto clean_exit;
}
@ -103,17 +111,24 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
}
srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz);
q->sf_symbols = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t));
if (!q->sf_symbols) {
perror("malloc");
goto clean_exit;
}
for (uint32_t i=0;i<q->cell.nof_ports;i++) {
q->ce[i] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t));
if (!q->ce[i]) {
for (int j=0;j<nof_rx_antennas;j++) {
q->sf_symbols_m[j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t));
if (!q->sf_symbols_m[j]) {
perror("malloc");
goto clean_exit;
}
for (uint32_t i=0;i<q->cell.nof_ports;i++) {
q->ce_m[i][j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t));
if (!q->ce_m[i][j]) {
perror("malloc");
goto clean_exit;
}
}
}
q->sf_symbols = q->sf_symbols_m[0];
for (int i=0;i<q->cell.nof_ports;i++) {
q->ce[i] = q->ce_m[i][0];
}
ret = SRSLTE_SUCCESS;
@ -140,12 +155,14 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
srslte_pdsch_free(&q->pdsch);
srslte_cfo_free(&q->sfo_correct);
srslte_softbuffer_rx_free(&q->softbuffer);
if (q->sf_symbols) {
free(q->sf_symbols);
}
for (uint32_t i=0;i<q->cell.nof_ports;i++) {
if (q->ce[i]) {
free(q->ce[i]);
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->sf_symbols_m[j]) {
free(q->sf_symbols_m[j]);
}
for (uint32_t i=0;i<q->cell.nof_ports;i++) {
if (q->ce_m[i][j]) {
free(q->ce_m[i][j]);
}
}
}
bzero(q, sizeof(srslte_ue_dl_t));
@ -187,22 +204,38 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
* - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti()
*/
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) {
return srslte_ue_dl_decode_rnti(q, input, data, tti, q->current_rnti);
cf_t *_input[SRSLTE_MAX_PORTS];
_input[0] = input;
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, q->current_rnti);
}
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) {
int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti) {
return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti);
}
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi)
{
cf_t *_input[SRSLTE_MAX_PORTS];
_input[0] = input;
return srslte_ue_dl_decode_fft_estimate_multi(q, _input, sf_idx, cfi);
}
int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi)
{
if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Run FFT for all subframe data */
srslte_ofdm_rx_sf(&q->fft, input, q->sf_symbols);
/* Correct SFO multiplying by complex exponential in the time domain */
if (q->sample_offset) {
for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) {
srslte_cfo_correct(&q->sfo_correct,
&q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE],
&q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE],
q->sample_offset / q->fft.symbol_sz);
for (int j=0;j<q->nof_rx_antennas;j++) {
srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]);
/* Correct SFO multiplying by complex exponential in the time domain */
if (q->sample_offset) {
for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) {
srslte_cfo_correct(&q->sfo_correct,
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
q->sample_offset / q->fft.symbol_sz);
}
}
}
return srslte_ue_dl_decode_estimate(q, sf_idx, cfi);
@ -216,10 +249,10 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c
if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Get channel estimates for each port */
srslte_chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx);
srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas);
/* First decode PCFICH and obtain CFI */
if (srslte_pcfich_decode(&q->pcfich, q->sf_symbols, q->ce,
if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m,
srslte_chest_dl_get_noise_estimate(&q->chest),
sf_idx, cfi, &cfi_corr)<0) {
fprintf(stderr, "Error decoding PCFICH\n");
@ -246,6 +279,13 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
}
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti)
{
cf_t *_input[SRSLTE_MAX_PORTS];
_input[0] = input;
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, rnti);
}
int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti, uint16_t rnti)
{
srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked;
@ -255,11 +295,15 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint
uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) {
if ((ret = srslte_ue_dl_decode_fft_estimate_multi(q, input, sf_idx, &cfi)) < 0) {
return ret;
}
if (srslte_pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi)) {
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
// Uncoment next line to do ZF by default in pdsch_ue example
//float noise_estimate = 0;
if (srslte_pdcch_extract_llr_multi(&q->pdcch, q->sf_symbols_m, q->ce_m, noise_estimate, sf_idx, cfi)) {
fprintf(stderr, "Error extracting LLRs\n");
return SRSLTE_ERROR;
}
@ -294,13 +338,10 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint
q->nof_detected++;
// Uncoment next line to do ZF by default in pdsch_ue example
//float noise_estimate = 0;
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) {
ret = srslte_pdsch_decode(&q->pdsch, &q->pdsch_cfg, &q->softbuffer,
q->sf_symbols, q->ce,
ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, &q->softbuffer,
q->sf_symbols_m, q->ce_m,
noise_estimate,
rnti, data);
@ -502,7 +543,14 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr
INFO("Decoding PHICH sf_idx=%d, n_prb_lowest=%d, n_dmrs=%d, n_group=%d, n_seq=%d, Ngroups=%d, Nsf=%d\n",
sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq,
srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich));
if (!srslte_phich_decode(&q->phich, q->sf_symbols, q->ce, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) {
cf_t *ce0[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ce0[i] = q->ce_m[i][0];
}
if (!srslte_phich_decode(&q->phich, q->sf_symbols_m[0], ce0, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) {
INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance);
} else {
fprintf(stderr, "Error decoding PHICH\n");
@ -516,11 +564,11 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr
}
void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuffer, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) {
srslte_vec_save_file("sf_symbols", q->sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
srslte_vec_save_file("sf_symbols", q->sf_symbols_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
printf("%d samples\n", SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp));
srslte_vec_save_file("ce0", q->ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
srslte_vec_save_file("ce0", q->ce_m[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
if (q->cell.nof_ports > 1) {
srslte_vec_save_file("ce1", q->ce[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
srslte_vec_save_file("ce1", q->ce_m[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
}
srslte_vec_save_file("pcfich_ce0", q->pcfich.ce[0], q->pcfich.nof_symbols*sizeof(cf_t));
srslte_vec_save_file("pcfich_ce1", q->pcfich.ce[1], q->pcfich.nof_symbols*sizeof(cf_t));

View File

@ -161,13 +161,11 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input,
return ret;
}
int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q,
uint32_t cell_id,
srslte_cp_t cp,
int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*),
void *stream_handler)
uint32_t cell_id,
srslte_cp_t cp,
int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*),
void *stream_handler)
{
srslte_cell_t cell;
// If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports
@ -176,6 +174,9 @@ int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q,
cell.cp = cp;
cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB;
q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
q->nof_rx_antennas = 1;
if (srslte_ue_mib_init(&q->ue_mib, cell)) {
fprintf(stderr, "Error initiating ue_mib\n");
return SRSLTE_ERROR;
@ -189,7 +190,44 @@ int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q,
return SRSLTE_SUCCESS;
}
int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q,
uint32_t cell_id,
srslte_cp_t cp,
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void *stream_handler)
{
srslte_cell_t cell;
// If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports
cell.nof_ports = 0;
cell.id = cell_id;
cell.cp = cp;
cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB;
for (int i=0;i<nof_rx_antennas;i++) {
q->sf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
q->nof_rx_antennas = nof_rx_antennas;
if (srslte_ue_mib_init(&q->ue_mib, cell)) {
fprintf(stderr, "Error initiating ue_mib\n");
return SRSLTE_ERROR;
}
if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) {
fprintf(stderr, "Error initiating ue_sync\n");
srslte_ue_mib_free(&q->ue_mib);
return SRSLTE_ERROR;
}
srslte_ue_sync_decode_sss_on_track(&q->ue_sync, true);
return SRSLTE_SUCCESS;
}
void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q) {
for (int i=0;i<q->nof_rx_antennas;i++) {
if (q->sf_buffer[i]) {
free(q->sf_buffer[i]);
}
}
srslte_ue_mib_free(&q->ue_mib);
srslte_ue_sync_free(&q->ue_sync);
}
@ -207,7 +245,6 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q,
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
cf_t *sf_buffer = NULL;
uint32_t nof_frames = 0;
int mib_ret = SRSLTE_UE_MIB_NOTFOUND;
@ -216,13 +253,13 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q,
ret = SRSLTE_SUCCESS;
do {
mib_ret = SRSLTE_UE_MIB_NOTFOUND;
ret = srslte_ue_sync_get_buffer(&q->ue_sync, &sf_buffer);
ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
break;
} else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) {
if (ret == 1) {
mib_ret = srslte_ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset);
mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset);
} else {
DEBUG("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt);
srslte_ue_mib_reset(&q->ue_mib);

View File

@ -39,7 +39,6 @@
#define MAX_TIME_OFFSET 128
cf_t dummy[MAX_TIME_OFFSET];
#define TRACK_MAX_LOST 4
#define TRACK_FRAME_SIZE 32
@ -47,7 +46,11 @@ cf_t dummy[MAX_TIME_OFFSET];
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0
#define DEFAULT_SFO_EMA_COEFF 0.1
cf_t dummy_offset_buffer[1024*1024];
cf_t dummy_buffer0[15*2048/2];
cf_t dummy_buffer1[15*2048/2];
// FIXME: this will break for 4 antennas!!
cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1};
int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, float offset_freq) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -74,12 +77,6 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n
goto clean_exit;
}
q->input_buffer = srslte_vec_malloc(2 * q->sf_len * sizeof(cf_t));
if (!q->input_buffer) {
perror("malloc");
goto clean_exit;
}
INFO("Offseting input file by %d samples and %.1f kHz\n", offset_time, offset_freq/1000);
srslte_filesource_read(&q->file_source, dummy_offset_buffer, offset_time);
@ -109,16 +106,33 @@ int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(voi
return n;
}
int recv_callback_multi_to_single(void *h, cf_t *x[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t*t)
{
srslte_ue_sync_t *q = (srslte_ue_sync_t*) h;
return q->recv_callback_single(q->stream, (void*) x[0], nsamples, t);
}
int srslte_ue_sync_init(srslte_ue_sync_t *q,
srslte_cell_t cell,
int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*),
int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*),
void *stream_handler)
{
q->recv_callback_single = recv_callback;
return srslte_ue_sync_init_multi(q, cell, recv_callback_multi_to_single, 1, q);
}
int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
srslte_cell_t cell,
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void *stream_handler)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
stream_handler != NULL &&
srslte_nofprb_isvalid(cell.nof_prb) &&
srslte_nofprb_isvalid(cell.nof_prb) &&
nof_rx_antennas <= SRSLTE_MAX_PORTS &&
recv_callback != NULL)
{
ret = SRSLTE_ERROR;
@ -127,6 +141,7 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q,
q->stream = stream_handler;
q->recv_callback = recv_callback;
q->nof_rx_antennas = nof_rx_antennas;
q->cell = cell;
q->fft_size = srslte_symbol_sz(q->cell.nof_prb);
q->sf_len = SRSLTE_SF_LEN(q->fft_size);
@ -209,13 +224,6 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q,
}
/* FIXME: Go for zerocopy only and eliminate this allocation */
q->input_buffer = srslte_vec_malloc(2*q->frame_len * sizeof(cf_t));
if (!q->input_buffer) {
perror("malloc");
goto clean_exit;
}
srslte_ue_sync_reset(q);
ret = SRSLTE_SUCCESS;
@ -233,9 +241,6 @@ uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q) {
}
void srslte_ue_sync_free(srslte_ue_sync_t *q) {
if (q->input_buffer) {
free(q->input_buffer);
}
if (q->do_agc) {
srslte_agc_free(&q->agc);
}
@ -309,7 +314,7 @@ void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period) {
q->agc_period = period;
}
static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer) {
static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) {
if (srslte_sync_sss_detected(&q->sfind)) {
@ -408,7 +413,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) {
discard the offseted samples to align next frame */
if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) {
DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset);
if (q->recv_callback(q->stream, dummy, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) {
if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) {
fprintf(stderr, "Error receiving from USRP\n");
return SRSLTE_ERROR;
}
@ -443,7 +448,7 @@ static int track_peak_no(srslte_ue_sync_t *q) {
}
static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) {
static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) {
/* A negative time offset means there are samples in our buffer for the next subframe,
because we are sampling too fast.
@ -453,7 +458,11 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) {
}
/* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */
if (q->recv_callback(q->stream, &input_buffer[q->next_rf_sample_offset], q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) {
cf_t *ptr[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ptr[i] = &input_buffer[i][q->next_rf_sample_offset];
}
if (q->recv_callback(q->stream, ptr, q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) {
return SRSLTE_ERROR;
}
@ -465,17 +474,14 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) {
bool first_track = true;
int srslte_ue_sync_get_buffer(srslte_ue_sync_t *q, cf_t **sf_symbols) {
int ret = srslte_ue_sync_zerocopy(q, q->input_buffer);
if (sf_symbols) {
*sf_symbols = q->input_buffer;
}
return ret;
int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
cf_t *_input_buffer[SRSLTE_MAX_PORTS];
_input_buffer[0] = input_buffer;
return srslte_ue_sync_zerocopy_multi(q, _input_buffer);
}
/* Returns 1 if the subframe is synchronized in time, 0 otherwise */
int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t track_idx;
@ -484,7 +490,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
{
if (q->file_mode) {
int n = srslte_filesource_read(&q->file_source, input_buffer, q->sf_len);
int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len);
if (n < 0) {
fprintf(stderr, "Error reading input file\n");
return SRSLTE_ERROR;
@ -492,7 +498,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
if (n == 0) {
srslte_filesource_seek(&q->file_source, 0);
q->sf_idx = 9;
int n = srslte_filesource_read(&q->file_source, input_buffer, q->sf_len);
int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len);
if (n < 0) {
fprintf(stderr, "Error reading input file\n");
return SRSLTE_ERROR;
@ -500,8 +506,8 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
}
if (q->correct_cfo) {
srslte_cfo_correct(&q->file_cfo_correct,
input_buffer,
input_buffer,
input_buffer[0],
input_buffer[0],
q->file_cfo / 15000 / q->fft_size);
}
@ -519,7 +525,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
switch (q->state) {
case SF_FIND:
switch(srslte_sync_find(&q->sfind, input_buffer, 0, &q->peak_idx)) {
switch(srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx)) {
case SRSLTE_SYNC_ERROR:
ret = SRSLTE_ERROR;
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
@ -539,7 +545,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
break;
}
if (q->do_agc) {
srslte_agc_process(&q->agc, input_buffer, q->sf_len);
srslte_agc_process(&q->agc, input_buffer[0], q->sf_len);
}
break;
@ -557,7 +563,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
if (q->do_agc && (q->agc_period == 0 ||
(q->agc_period && (q->frame_total_cnt%q->agc_period) == 0)))
{
srslte_agc_process(&q->agc, input_buffer, q->sf_len);
srslte_agc_process(&q->agc, input_buffer[0], q->sf_len);
}
#ifdef MEASURE_EXEC_TIME
@ -570,7 +576,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
/* Track PSS/SSS around the expected PSS position
* In tracking phase, the subframe carrying the PSS is always the last one of the frame
*/
switch(srslte_sync_find(&q->strack, input_buffer,
switch(srslte_sync_find(&q->strack, input_buffer[0],
q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2,
&track_idx))
{
@ -607,10 +613,12 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
q->frame_total_cnt++;
}
if (q->correct_cfo) {
srslte_cfo_correct(&q->sfind.cfocorr,
input_buffer,
input_buffer,
for (int i=0;i<q->nof_rx_antennas;i++) {
srslte_cfo_correct(&q->sfind.cfocorr,
input_buffer[i],
input_buffer[i],
-srslte_sync_get_cfo(&q->strack) / q->fft_size);
}
}
break;
}