mirror of https://github.com/PentHertz/srsLTE.git
Merge branch '2rx' into next
This commit is contained in:
commit
58b5791827
|
@ -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)))
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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]);
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue