Improved SFBC decoder and added SSE version. Fixed bug in MIB decoding. Improved calibration of synchronization constants

master
ismagom 9 years ago
parent 799af37bed
commit c3268a93e2

@ -0,0 +1,46 @@
clear
addpath('../../build/srslte/lib/mimo/test')
enb = lteRMCDL('R.10');
cec = struct('FreqWindow',9,'TimeWindow',9,'InterpType','cubic');
cec.PilotAverage = 'UserDefined';
cec.InterpWinSize = 1;
cec.InterpWindow = 'Causal';
cfg.Seed = 1; % Random channel seed
cfg.NRxAnts = 1; % 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
[txWaveform, ~, info] = lteRMCDLTool(enb,[1;0;0;1]);
n = length(txWaveform);
cfg.SamplingRate = info.SamplingRate;
txWaveform = txWaveform+complex(randn(n,2),randn(n,2))*1e-3;
rxWaveform = lteFadingChannel(cfg,txWaveform);
rxGrid = lteOFDMDemodulate(enb,sum(rxWaveform,2));
[h,n0] = lteDLChannelEstimate(enb,cec,rxGrid);
signal=rxGrid(:,1);
hest(:,1,1)=reshape(h(:,1,1,1),[],1);
hest(:,1,2)=reshape(h(:,1,1,1),[],1);
output_mat = lteTransmitDiversityDecode(signal(, hest(1:598,1,:));
output_srs = srslte_diversitydecode(signal(1:598), hest(1:598,1,:));
plot(abs(output_mat-output_srs))
mean(abs(output_mat-output_srs).^2)

@ -1,18 +1,10 @@
%clear clear
% R.1 10 MHz 1 port
% R.10 10 MHz 2 ports
% R.4 1.4 MHz 1 port
% R.11-2 5 MHz 2 ports
rmc = lteRMCDL('R.10');
NofPortsTx=1; Nblock=[3];
SNR_values_db=100;%linspace(-4,0,6);
SNR_values_db=1;%linspace(-8,-2,4); Nrealizations=1;
Nrealizations=5; enb = struct('NCellID',62,'NDLRB',50,'CellRefP',2,'CyclicPrefix','Normal','DuplexMode','FDD',...
enb = struct('NCellID',1,'NDLRB',25,'CellRefP',NofPortsTx,'CyclicPrefix','Normal','DuplexMode','FDD','NSubframe',0); 'NSubframe',0,'PHICHDuration','Normal','Ng','One','NFrame',101,'TotSubframes',40);
griddims = lteResourceGridSize(enb); % Resource grid dimensions
L = griddims(2);
cfg.Seed = 8; % Random channel seed cfg.Seed = 8; % Random channel seed
cfg.NRxAnts = 1; % 1 receive antenna cfg.NRxAnts = 1; % 1 receive antenna
@ -33,44 +25,66 @@ cec.InterpType = 'linear'; % 2D interpolation type
cec.InterpWindow = 'Centered'; % Interpolation window type cec.InterpWindow = 'Centered'; % Interpolation window type
cec.InterpWinSize = 1; % Interpolation window size cec.InterpWinSize = 1; % Interpolation window size
rmc.PDSCH.Modulation = '16QAM'; griddims = lteResourceGridSize(enb); % Resource grid dimensions
[waveform,rgrid,info] = lteRMCDLTool(rmc,[1;0;0;1]); L = griddims(2);
cfg.SamplingRate = info.SamplingRate;
addpath('../../debug/lte/phy/lib/phch/test')
% Generate signal
mib = lteMIB(enb);
bchCoded = lteBCH(enb,mib);
mibCRC = lteCRCEncode(mib,'16');
mibCoded = lteConvolutionalEncode(mibCRC);
pbchSymbolsTx = ltePBCH(enb,bchCoded);
pbchIndtx = ltePBCHIndices(enb);
subframe_tx = lteDLResourceGrid(enb);
rs = lteCellRS(enb);
rsind = lteCellRSIndices(enb);
subframe_tx(rsind)=rs;
NofPortsTx=enb.CellRefP;
addpath('../../build/srslte/lib/phch/test')
txWaveform=cell(length(Nblock));
rxWaveform=cell(length(Nblock));
for n=1:length(Nblock)
subframe_tx2=subframe_tx;
subframe_tx2(pbchIndtx)=pbchSymbolsTx(Nblock(n)*240+1:(Nblock(n)+1)*240,:);
[txWaveform{n},info] = lteOFDMModulate(enb, subframe_tx2, 0);
cfg.SamplingRate = info.SamplingRate;
end
error=zeros(length(SNR_values_db),2); error=zeros(length(SNR_values_db),2);
for snr_idx=1:length(SNR_values_db) for snr_idx=1:length(SNR_values_db)
SNRdB = SNR_values_db(snr_idx); % Desired SNR in dB SNRdB = SNR_values_db(snr_idx); % Desired SNR in dB
SNR = 10^(SNRdB/20); % Linear SNR SNR = 10^(SNRdB/10); % Linear SNR
errorReal = zeros(Nrealizations,2); errorReal = zeros(Nrealizations,2);
for i=1:Nrealizations for i=1:Nrealizations
rxWaveform = lteFadingChannel(cfg,sum(waveform,2)); for n=1:length(Nblock)
%rxWaveform = lteFadingChannel(cfg,sum(txWaveform,2));
rxWaveform{n} = sum(txWaveform{n},2);
%% Additive Noise %% Additive Noise
N0 = 1/(sqrt(2.0*double(enb.CellRefP)*double(info.Nfft))*SNR); N0 = 1/(sqrt(2.0*double(enb.CellRefP)*double(info.Nfft))*SNR);
% Create additive white Gaussian noise % Create additive white Gaussian noise
noise = N0*complex(randn(size(rxWaveform)),randn(size(rxWaveform))); noise = N0*complex(randn(size(rxWaveform{n})),randn(size(rxWaveform{n})));
rxWaveform = noise + rxWaveform; rxWaveform{n} = noise + rxWaveform{n};
rxWaveform = x((i-1)*76800+1:i*76800);
% Number of OFDM symbols in a subframe % Number of OFDM symbols in a subframe
% OFDM demodulate signal % OFDM demodulate signal
rxgrid = lteOFDMDemodulate(enb, rxWaveform); rxgrid = lteOFDMDemodulate(enb, rxWaveform{n}, 0);
% Perform channel estimation % Perform channel estimation
%enb.CellRefP=2;
[hest, nest] = lteDLChannelEstimate(enb, cec, rxgrid(:,1:L,:)); [hest, nest] = lteDLChannelEstimate(enb, cec, rxgrid(:,1:L,:));
pbchIndices = ltePBCHIndices(enb); pbchIndices = ltePBCHIndices(enb);
[pbchRx, pbchHest] = lteExtractResources( ... [pbchRx, pbchHest] = lteExtractResources(pbchIndices, rxgrid(:,1:L,:), ...
pbchIndices, rxgrid(:,1:L,:), hest(:,1:L,:,:)); hest(:,1:L,:,:));
% Decode PBCH % Decode PBCH
[bchBits, pbchSymbols, nfmod4, mib, nof_ports] = ltePBCHDecode(enb, pbchRx, pbchHest, nest); [bchBits, pbchSymbols, nfmod4, mib, nof_ports] = ltePBCHDecode(enb, pbchRx, pbchHest, nest);
@ -78,14 +92,24 @@ for snr_idx=1:length(SNR_values_db)
if (nof_ports ~= NofPortsTx) if (nof_ports ~= NofPortsTx)
errorReal(i,1)=1; errorReal(i,1)=1;
end end
end
%enb.CellRefP=NofPortsTx;
[nof_ports2, pbchSymbols2, pbchBits, ce, ce2, pbchRx2, pbchHest2, mod2, codedbits]= ...
srslte_pbch(enb, rxWaveform);
subplot(2,1,1)
plot(abs((bchCoded(1:960)>0)-(pbchBits(1:960)>0)))
subplot(2,1,2)
codedbits2 = reshape(reshape(codedbits,3,[])',1,[]);
plot(abs((codedbits2'>0)-(mibCoded>0)))
%decodedData = lteConvolutionalDecode(noisysymbols);
%[decodedData2, quant] = srslte_viterbi(interleavedSymbols);
[nof_ports2, pbchSymbols2, pbchBits, ce, ce2, pbchRx2, pbchHest2]= srslte_pbch(enb, rxWaveform, hest, nest);
if (nof_ports2 ~= NofPortsTx) if (nof_ports2 ~= NofPortsTx)
errorReal(i,2)=1; errorReal(i,2)=1;
end end
% if (errorReal(i,1) ~= errorReal(i,2))
% i=1;
% end
end end
error(snr_idx,:) = sum(errorReal); error(snr_idx,:) = sum(errorReal);
fprintf('SNR: %.2f dB\n', SNR_values_db(snr_idx)); fprintf('SNR: %.2f dB\n', SNR_values_db(snr_idx));
@ -100,5 +124,7 @@ if (length(SNR_values_db) > 1)
axis([min(SNR_values_db) max(SNR_values_db) 1/Nrealizations/10 1]) axis([min(SNR_values_db) max(SNR_values_db) 1/Nrealizations/10 1])
else else
disp(error) disp(error)
disp(nfmod4)
disp(mod2)
end end

@ -5,25 +5,25 @@
% A structure |enbConfig| is used to configure the eNodeB. % A structure |enbConfig| is used to configure the eNodeB.
clear clear
Npackets = 1; Npackets = 60;
SNR_values = 100;%linspace(-5,0,8); SNR_values = linspace(2,6,6);
txCFI = 1; txCFI = 3;
enbConfig.NDLRB = 50; % No of Downlink RBs in total BW enbConfig.NDLRB = 15; % No of Downlink RBs in total BW
enbConfig.CyclicPrefix = 'Normal'; % CP length enbConfig.CyclicPrefix = 'Normal'; % CP length
enbConfig.CFI = txCFI; ; % 4 PDCCH symbols as NDLRB <= 10 enbConfig.CFI = txCFI; ; % 4 PDCCH symbols as NDLRB <= 10
enbConfig.Ng = 'One'; % HICH groups enbConfig.Ng = 'One'; % HICH groups
enbConfig.CellRefP = 2; % 1-antenna ports enbConfig.CellRefP = 1; % 1-antenna ports
enbConfig.NCellID = 424; % Physical layer cell identity enbConfig.NCellID = 0; % Physical layer cell identity
enbConfig.NSubframe = 5; % Subframe number 0 enbConfig.NSubframe = 5; % Subframe number 0
enbConfig.DuplexMode = 'FDD'; % Frame structure enbConfig.DuplexMode = 'FDD'; % Frame structure
enbConfig.PHICHDuration = 'Normal'; enbConfig.PHICHDuration = 'Normal';
C_RNTI = 65535; % 16-bit UE-specific mask C_RNTI = 1; % 16-bit UE-specific mask
%% Setup Fading channel model %% Setup Fading channel model
cfg.Seed = 8; % Random channel seed cfg.Seed = 8; % Random channel seed
cfg.NRxAnts = 1; % 1 receive antenna cfg.NRxAnts = 1; % 1 receive antenna
cfg.DelayProfile = 'EPA'; % EVA delay spread cfg.DelayProfile = 'EVA'; % EVA delay spread
cfg.DopplerFreq = 5; % 120Hz Doppler frequency cfg.DopplerFreq = 5; % 120Hz Doppler frequency
cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation
cfg.InitTime = 0; % Initialize at time zero cfg.InitTime = 0; % Initialize at time zero
@ -56,7 +56,7 @@ dciConfig.Allocation.RIV = 26; % Resource indication value
if C_RNTI<65535 if C_RNTI<65535
pdcchConfig.RNTI = C_RNTI; % Radio network temporary identifier pdcchConfig.RNTI = C_RNTI; % Radio network temporary identifier
end end
pdcchConfig.PDCCHFormat = 2; % PDCCH format pdcchConfig.PDCCHFormat = 0; % PDCCH format
ueConfig.RNTI = C_RNTI; ueConfig.RNTI = C_RNTI;
candidates = ltePDCCHSpace(enbConfig, pdcchConfig, {'bits', '1based'}); candidates = ltePDCCHSpace(enbConfig, pdcchConfig, {'bits', '1based'});
@ -153,7 +153,7 @@ for snr_idx=1:length(SNR_values)
%% Same with srsLTE %% Same with srsLTE
[rxCFI_srslte, pcfichRx2, pcfichSymbols2] = srslte_pcfich(enbConfigRx, subframe_rx); [rxCFI_srslte, pcfichRx2, pcfichSymbols2] = srslte_pcfich(enbConfigRx, subframe_rx);
decoded_cfi_srslte(snr_idx) = decoded_cfi_srslte(snr_idx) + (rxCFI_srslte == txCFI); decoded_cfi_srslte(snr_idx) = decoded_cfi_srslte(snr_idx) + (rxCFI_srslte == txCFI);
enbConfigRx.CFI = rxCFI_srslte; enbConfigRx.CFI = rxCFI;
[found_srslte, pdcchBits2, pdcchRx2, pdcchSymbols2, hest2] = srslte_pdcch(enbConfigRx, ueConfig.RNTI, subframe_rx, hest, nest); [found_srslte, pdcchBits2, pdcchRx2, pdcchSymbols2, hest2] = srslte_pdcch(enbConfigRx, ueConfig.RNTI, subframe_rx, hest, nest);
decoded_srslte(snr_idx) = decoded_srslte(snr_idx)+found_srslte; decoded_srslte(snr_idx) = decoded_srslte(snr_idx)+found_srslte;
end end
@ -172,12 +172,6 @@ if (Npackets>1)
axis([min(SNR_values) max(SNR_values) 1/Npackets/10 1]) axis([min(SNR_values) max(SNR_values) 1/Npackets/10 1])
else else
%scatter(real(pdcchSymbols2),imag(pdcchSymbols2))
%hold on
%scatter(real(pdcchSymbols),imag(pdcchSymbols))
%axis([-1.5 1.5 -1.5 1.5])
%hold off
n=min(length(pdcchSymbols),length(pdcchSymbols2)); n=min(length(pdcchSymbols),length(pdcchSymbols2));
subplot(2,1,1) subplot(2,1,1)
plot(abs(pdcchSymbols(1:n)-pdcchSymbols2(1:n))) plot(abs(pdcchSymbols(1:n)-pdcchSymbols2(1:n)))
@ -186,6 +180,9 @@ else
pdcchBitsTx(pdcchBitsTx==-1)=0; pdcchBitsTx(pdcchBitsTx==-1)=0;
plot(abs((pdcchBitsTx(1:n)>0.1)-(pdcchBits2(1:n)>0.1))) plot(abs((pdcchBitsTx(1:n)>0.1)-(pdcchBits2(1:n)>0.1)))
subplot(1,1,1)
plot(1:180,real(hest(:,1,1,1)),1:180,real(hest2(1:180)))
disp(decoded) disp(decoded)
disp(decoded_srslte) disp(decoded_srslte)
end end

@ -53,7 +53,7 @@ char *mexutils_get_char_struct(const mxArray *ptr, const char *field_name) {
mxArray *p; mxArray *p;
p = mxGetField(ptr, 0, field_name); p = mxGetField(ptr, 0, field_name);
if (!p) { if (!p) {
return NULL; return "";
} }
if (mxIsCell(p)) { if (mxIsCell(p)) {

@ -40,10 +40,10 @@
#include "srslte/rf/rf_utils.h" #include "srslte/rf/rf_utils.h"
cell_search_cfg_t cell_detect_config = { cell_search_cfg_t cell_detect_config = {
5000, // maximum number of frames to receive for MIB decoding 500,
50, // maximum number of frames to receive for PSS correlation 50,
10.0, 10,
50.0 0
}; };
/********************************************************************** /**********************************************************************
@ -153,6 +153,7 @@ int main(int argc, char **argv) {
int sfn_offset; int sfn_offset;
float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0; float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0;
cf_t *ce[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS];
float cfo = 0;
if (parse_args(&prog_args, argc, argv)) { if (parse_args(&prog_args, argc, argv)) {
exit(-1); exit(-1);
@ -191,7 +192,7 @@ int main(int argc, char **argv) {
uint32_t ntrial=0; uint32_t ntrial=0;
do { do {
ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell); ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error searching for cell\n"); fprintf(stderr, "Error searching for cell\n");
exit(-1); exit(-1);
@ -267,6 +268,9 @@ int main(int argc, char **argv) {
float rx_gain_offset = 0; float rx_gain_offset = 0;
// Set initial CFO for ue_sync
srslte_ue_sync_set_cfo(&ue_sync, cfo);
/* Main loop */ /* Main loop */
while ((sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) && !go_exit) { while ((sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) && !go_exit) {

@ -55,11 +55,12 @@
int band = -1; int band = -1;
int earfcn_start=-1, earfcn_end = -1; int earfcn_start=-1, earfcn_end = -1;
cell_search_cfg_t config = {
50, // maximum number of 5ms frames to capture for MIB decoding cell_search_cfg_t cell_detect_config = {
50, // maximum number of 5ms frames to capture for PSS correlation 500,
4.0, // early-stops cell detection if mean PSR is above this value 50,
0 // 0 or negative to disable AGC 10,
0
}; };
struct cells { struct cells {
@ -80,13 +81,12 @@ void usage(char *prog) {
printf("\t-s earfcn_start [Default All]\n"); printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n"); printf("\t-e earfcn_end [Default All]\n");
printf("\t-n nof_frames_total [Default 100]\n"); printf("\t-n nof_frames_total [Default 100]\n");
printf("\t-t threshold [Default %.2f]\n",config.threshold);
printf("\t-v [set srslte_verbose to debug, default none]\n"); printf("\t-v [set srslte_verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "agsendtvb")) != -1) { while ((opt = getopt(argc, argv, "agsendvb")) != -1) {
switch(opt) { switch(opt) {
case 'a': case 'a':
rf_args = argv[optind]; rf_args = argv[optind];
@ -101,10 +101,7 @@ void parse_args(int argc, char **argv) {
earfcn_end = atoi(argv[optind]); earfcn_end = atoi(argv[optind]);
break; break;
case 'n': case 'n':
config.max_frames_pss = atoi(argv[optind]); cell_detect_config.max_frames_pss = atoi(argv[optind]);
break;
case 't':
config.threshold = atof(argv[optind]);
break; break;
case 'g': case 'g':
rf_gain = atof(argv[optind]); rf_gain = atof(argv[optind]);
@ -159,7 +156,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error opening rf\n"); fprintf(stderr, "Error opening rf\n");
exit(-1); exit(-1);
} }
if (!config.init_agc) { if (!cell_detect_config.init_agc) {
srslte_rf_set_rx_gain(&rf, rf_gain); srslte_rf_set_rx_gain(&rf, rf_gain);
} else { } else {
printf("Starting AGC thread...\n"); printf("Starting AGC thread...\n");
@ -203,19 +200,16 @@ int main(int argc, char **argv) {
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, srslte_rf_recv_wrapper, (void*) &rf)) { if (srslte_ue_cellsearch_init(&cs, cell_detect_config.max_frames_pss, srslte_rf_recv_wrapper, (void*) &rf)) {
fprintf(stderr, "Error initiating UE cell detect\n"); fprintf(stderr, "Error initiating UE cell detect\n");
exit(-1); exit(-1);
} }
if (config.max_frames_pss) { if (cell_detect_config.max_frames_pss) {
srslte_ue_cellsearch_set_nof_frames_to_scan(&cs, config.max_frames_pss); srslte_ue_cellsearch_set_nof_valid_frames(&cs, cell_detect_config.nof_valid_pss_frames);
}
if (config.threshold) {
srslte_ue_cellsearch_set_threshold(&cs, config.threshold);
} }
if (config.init_agc) { if (cell_detect_config.init_agc) {
srslte_ue_sync_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_wrapper, config.init_agc); srslte_ue_sync_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_wrapper, cell_detect_config.init_agc);
} }
INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000); INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000);
@ -229,11 +223,11 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} else if (n > 0) { } else if (n > 0) {
for (int i=0;i<3;i++) { for (int i=0;i<3;i++) {
if (found_cells[i].psr > config.threshold/2) { if (found_cells[i].psr > 10.0) {
srslte_cell_t cell; srslte_cell_t cell;
cell.id = found_cells[i].cell_id; cell.id = found_cells[i].cell_id;
cell.cp = found_cells[i].cp; cell.cp = found_cells[i].cp;
int ret = rf_mib_decoder(&rf, &config, &cell); int ret = rf_mib_decoder(&rf, &cell_detect_config, &cell, NULL);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error decoding MIB\n"); fprintf(stderr, "Error decoding MIB\n");
exit(-1); exit(-1);

@ -39,15 +39,20 @@
#include "srslte/srslte.h" #include "srslte/srslte.h"
// From srsLTE 1.2, AGC is disabled by default
//#define ENABLE_AGC_DEFAULT
#ifndef DISABLE_RF #ifndef DISABLE_RF
#include "srslte/rf/rf.h" #include "srslte/rf/rf.h"
#include "srslte/rf/rf_utils.h" #include "srslte/rf/rf_utils.h"
cell_search_cfg_t cell_detect_config = { cell_search_cfg_t cell_detect_config = {
5000, 500,
200, // nof_frames_total 50,
10.0 // threshold 10,
0
}; };
#else #else
#warning Compiling pdsch_ue with no RF support #warning Compiling pdsch_ue with no RF support
#endif #endif
@ -110,7 +115,11 @@ void args_default(prog_args_t *args) {
args->file_offset_freq = 0; args->file_offset_freq = 0;
args->rf_args = ""; args->rf_args = "";
args->rf_freq = -1.0; args->rf_freq = -1.0;
#ifdef ENABLE_AGC_DEFAULT
args->rf_gain = -1.0; args->rf_gain = -1.0;
#else
args->rf_gain = 50.0;
#endif
args->net_port = -1; args->net_port = -1;
args->net_address = "127.0.0.1"; args->net_address = "127.0.0.1";
args->net_port_signal = -1; args->net_port_signal = -1;
@ -277,6 +286,7 @@ int main(int argc, char **argv) {
int n; int n;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
int sfn_offset; int sfn_offset;
float cfo = 0;
parse_args(&prog_args, argc, argv); parse_args(&prog_args, argc, argv);
@ -332,7 +342,7 @@ int main(int argc, char **argv) {
uint32_t ntrial=0; uint32_t ntrial=0;
do { do {
ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell); ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error searching for cell\n"); fprintf(stderr, "Error searching for cell\n");
exit(-1); exit(-1);
@ -440,6 +450,9 @@ int main(int argc, char **argv) {
ue_sync.correct_cfo = !prog_args.disable_cfo; ue_sync.correct_cfo = !prog_args.disable_cfo;
// Set initial CFO for ue_sync
srslte_ue_sync_set_cfo(&ue_sync, cfo);
INFO("\nEntering main loop...\n\n", 0); INFO("\nEntering main loop...\n\n", 0);
/* Main loop */ /* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
@ -478,7 +491,7 @@ int main(int argc, char **argv) {
decode_pdsch = true; decode_pdsch = true;
} else { } else {
/* We are looking for SIB1 Blocks, search only in appropiate places */ /* We are looking for SIB1 Blocks, search only in appropiate places */
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%8)==0)) {
decode_pdsch = true; decode_pdsch = true;
} else { } else {
decode_pdsch = false; decode_pdsch = false;
@ -486,6 +499,7 @@ int main(int argc, char **argv) {
} }
if (decode_pdsch) { if (decode_pdsch) {
INFO("Attempting DL decode SFN=%d\n", sfn);
if (prog_args.rnti != SRSLTE_SIRNTI) { if (prog_args.rnti != SRSLTE_SIRNTI) {
n = srslte_ue_dl_decode(&ue_dl, &sf_buffer[prog_args.time_offset], data, srslte_ue_sync_get_sfidx(&ue_sync)); n = srslte_ue_dl_decode(&ue_dl, &sf_buffer[prog_args.time_offset], data, srslte_ue_sync_get_sfidx(&ue_sync));
} else { } else {
@ -495,7 +509,14 @@ int main(int argc, char **argv) {
n = srslte_ue_dl_decode_rnti_rv(&ue_dl, &sf_buffer[prog_args.time_offset], data, n = srslte_ue_dl_decode_rnti_rv(&ue_dl, &sf_buffer[prog_args.time_offset], data,
srslte_ue_sync_get_sfidx(&ue_sync), srslte_ue_sync_get_sfidx(&ue_sync),
SRSLTE_SIRNTI, rv); SRSLTE_SIRNTI, rv);
/*
if (!n) {
printf("Saving signal...\n");
srslte_ue_dl_save_signal(&ue_dl, &ue_dl.softbuffer, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), rv); srslte_ue_dl_save_signal(&ue_dl, &ue_dl.softbuffer, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), rv);
exit(-1);
}
*/
} }
if (n < 0) { if (n < 0) {
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);

@ -45,37 +45,17 @@
*/ */
typedef struct {
cf_t *h_mod;
cf_t *tmp1;
cf_t *tmp2;
cf_t *tmp3;
float *y_mod;
float *z_real;
float *z_imag;
uint32_t max_frame_len;
} srslte_precoding_t;
SRSLTE_API int srslte_precoding_init(srslte_precoding_t *q,
uint32_t max_frame_len);
SRSLTE_API void srslte_precoding_free(srslte_precoding_t *q);
/* Generates the vector "y" from the input vector "x" /* Generates the vector "y" from the input vector "x"
*/ */
SRSLTE_API int srslte_precoding_single(srslte_precoding_t *q, SRSLTE_API int srslte_precoding_single(cf_t *x,
cf_t *x,
cf_t *y, cf_t *y,
int nof_symbols); int nof_symbols);
SRSLTE_API int srslte_precoding_diversity(srslte_precoding_t *q, SRSLTE_API int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
int nof_ports, int nof_symbols); int nof_ports, int nof_symbols);
SRSLTE_API int srslte_precoding_type(srslte_precoding_t *q, SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
int nof_layers, int nof_layers,
int nof_ports, int nof_ports,
@ -90,16 +70,13 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
int nof_symbols, int nof_symbols,
float noise_estimate); float noise_estimate);
SRSLTE_API int srslte_predecoding_diversity(srslte_precoding_t *q, SRSLTE_API int srslte_predecoding_diversity(cf_t *y,
cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_ports,
int nof_symbols, int nof_symbols);
float noise_estimate);
SRSLTE_API int srslte_predecoding_type(srslte_precoding_t *q, SRSLTE_API int srslte_predecoding_type(cf_t *y,
cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_ports,

@ -79,7 +79,6 @@ typedef struct SRSLTE_API {
srslte_viterbi_t decoder; srslte_viterbi_t decoder;
srslte_crc_t crc; srslte_crc_t crc;
srslte_convcoder_t encoder; srslte_convcoder_t encoder;
srslte_precoding_t precoding;
bool search_all_ports; bool search_all_ports;
} srslte_pbch_t; } srslte_pbch_t;

@ -73,7 +73,6 @@ typedef struct SRSLTE_API {
/* tx & rx objects */ /* tx & rx objects */
srslte_modem_table_t mod; srslte_modem_table_t mod;
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
srslte_precoding_t precoding;
} srslte_pcfich_t; } srslte_pcfich_t;

@ -80,7 +80,6 @@ typedef struct SRSLTE_API {
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
srslte_viterbi_t decoder; srslte_viterbi_t decoder;
srslte_crc_t crc; srslte_crc_t crc;
srslte_precoding_t precoding;
} srslte_pdcch_t; } srslte_pdcch_t;

@ -67,7 +67,6 @@ typedef struct SRSLTE_API {
srslte_modem_table_t mod[4]; srslte_modem_table_t mod[4];
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
srslte_precoding_t precoding;
srslte_sch_t dl_sch; srslte_sch_t dl_sch;

@ -80,7 +80,6 @@ typedef struct SRSLTE_API {
/* tx & rx objects */ /* tx & rx objects */
srslte_modem_table_t mod; srslte_modem_table_t mod;
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
srslte_precoding_t precoding;
} srslte_phich_t; } srslte_phich_t;

@ -73,8 +73,6 @@ typedef struct SRSLTE_API {
srslte_dft_precoding_t dft_precoding; srslte_dft_precoding_t dft_precoding;
srslte_precoding_t equalizer;
/* buffers */ /* buffers */
// void buffers are shared for tx and rx // void buffers are shared for tx and rx
cf_t *ce; cf_t *ce;

@ -29,9 +29,9 @@
#include "srslte/rf/rf.h" #include "srslte/rf/rf.h"
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint32_t max_frames_pbch; // maximum number of 5ms frames to capture for MIB decoding uint32_t max_frames_pbch; // timeout in number of 5ms frames for MIB decoding
uint32_t max_frames_pss; // maximum number of 5ms frames to capture for PSS correlation uint32_t max_frames_pss; // timeout in number of 5ms frames for synchronization
float threshold; // early-stops cell detection if mean PSR is above this value uint32_t nof_valid_pss_frames; // number of required synchronized frames
float init_agc; // 0 or negative to disable AGC float init_agc; // 0 or negative to disable AGC
} cell_search_cfg_t; } cell_search_cfg_t;
@ -44,16 +44,19 @@ SRSLTE_API int rf_rssi_scan(srslte_rf_t *rf,
SRSLTE_API int rf_mib_decoder(srslte_rf_t *rf, SRSLTE_API int rf_mib_decoder(srslte_rf_t *rf,
cell_search_cfg_t *config, cell_search_cfg_t *config,
srslte_cell_t *cell); srslte_cell_t *cell,
float *cfo);
SRSLTE_API int rf_cell_search(srslte_rf_t *rf, SRSLTE_API int rf_cell_search(srslte_rf_t *rf,
cell_search_cfg_t *config, cell_search_cfg_t *config,
int force_N_id_2, int force_N_id_2,
srslte_cell_t *cell); srslte_cell_t *cell,
float *cfo);
SRSLTE_API int rf_search_and_decode_mib(srslte_rf_t *rf, SRSLTE_API int rf_search_and_decode_mib(srslte_rf_t *rf,
cell_search_cfg_t *config, cell_search_cfg_t *config,
int force_N_id_2, int force_N_id_2,
srslte_cell_t *cell); srslte_cell_t *cell,
float *cfo);

@ -68,7 +68,6 @@ typedef struct SRSLTE_API {
float threshold; float threshold;
float peak_value; float peak_value;
float mean_peak_value;
uint32_t N_id_2; uint32_t N_id_2;
uint32_t N_id_1; uint32_t N_id_1;
uint32_t sf_idx; uint32_t sf_idx;
@ -97,6 +96,13 @@ typedef struct SRSLTE_API {
}srslte_sync_t; }srslte_sync_t;
typedef enum {
SRSLTE_SYNC_FOUND = 1,
SRSLTE_SYNC_FOUND_NOSPACE = 2,
SRSLTE_SYNC_NOFOUND = 0,
SRSLTE_SYNC_ERROR = -1
} srslte_sync_find_ret_t;
SRSLTE_API int srslte_sync_init(srslte_sync_t *q, SRSLTE_API int srslte_sync_init(srslte_sync_t *q,
uint32_t frame_size, uint32_t frame_size,
@ -108,7 +114,7 @@ SRSLTE_API void srslte_sync_free(srslte_sync_t *q);
SRSLTE_API void srslte_sync_reset(srslte_sync_t *q); SRSLTE_API void srslte_sync_reset(srslte_sync_t *q);
/* Finds a correlation peak in the input signal around position find_offset */ /* Finds a correlation peak in the input signal around position find_offset */
SRSLTE_API int srslte_sync_find(srslte_sync_t *q, SRSLTE_API srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q,
cf_t *input, cf_t *input,
uint32_t find_offset, uint32_t find_offset,
uint32_t *peak_position); uint32_t *peak_position);

@ -57,12 +57,6 @@
* TODO: Check also peak offset * TODO: Check also peak offset
*/ */
#define SRSLTE_CS_DEFAULT_MAXFRAMES_TOTAL 500
#define SRSLTE_CS_DEFAULT_MAXFRAMES_DETECTED 50
#define SRSLTE_CS_DEFAULT_NOFFRAMES_TOTAL 50
#define SRSLTE_CS_DEFAULT_NOFFRAMES_DETECTED 10
#define SRSLTE_CS_NOF_PRB 6 #define SRSLTE_CS_NOF_PRB 6
#define SRSLTE_CS_SAMP_FREQ 1920000.0 #define SRSLTE_CS_SAMP_FREQ 1920000.0
@ -80,8 +74,7 @@ typedef struct SRSLTE_API {
srslte_ue_sync_t ue_sync; srslte_ue_sync_t ue_sync;
uint32_t max_frames; uint32_t max_frames;
uint32_t nof_frames_to_scan; // number of 5 ms frames to scan uint32_t nof_valid_frames; // number of 5 ms frames to scan
float detect_threshold; // early-stops scan if mean PSR above this threshold
uint32_t *mode_ntimes; uint32_t *mode_ntimes;
uint8_t *mode_counted; uint8_t *mode_counted;
@ -89,12 +82,7 @@ typedef struct SRSLTE_API {
srslte_ue_cellsearch_result_t *candidates; srslte_ue_cellsearch_result_t *candidates;
} srslte_ue_cellsearch_t; } srslte_ue_cellsearch_t;
SRSLTE_API int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t *q, 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_max(srslte_ue_cellsearch_t *q,
uint32_t max_frames_total, uint32_t max_frames_total,
int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*),
void *stream_handler); void *stream_handler);
@ -109,12 +97,9 @@ SRSLTE_API int srslte_ue_cellsearch_scan(srslte_ue_cellsearch_t * q,
srslte_ue_cellsearch_result_t found_cells[3], srslte_ue_cellsearch_result_t found_cells[3],
uint32_t *max_N_id_2); uint32_t *max_N_id_2);
SRSLTE_API int srslte_ue_cellsearch_set_nof_frames_to_scan(srslte_ue_cellsearch_t *q, SRSLTE_API int srslte_ue_cellsearch_set_nof_valid_frames(srslte_ue_cellsearch_t *q,
uint32_t nof_frames); uint32_t nof_frames);
SRSLTE_API void srslte_ue_cellsearch_set_threshold(srslte_ue_cellsearch_t *q,
float threshold);

@ -41,8 +41,9 @@
#define ESTIMATE_NOISE_LS_PSS #define ESTIMATE_NOISE_LS_PSS
#define DEFAULT_FILTER_LEN 3 //#define DEFAULT_FILTER_LEN 3
#ifdef DEFAULT_FILTER_LEN
static void set_default_filter(srslte_chest_dl_t *q, int filter_len) { static void set_default_filter(srslte_chest_dl_t *q, int filter_len) {
float fil[SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN]; float fil[SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN];
@ -63,6 +64,7 @@ static void set_default_filter(srslte_chest_dl_t *q, int filter_len) {
srslte_chest_dl_set_smooth_filter(q, fil, filter_len); srslte_chest_dl_set_smooth_filter(q, fil, filter_len);
} }
#endif
/** 3GPP LTE Downlink channel estimator and equalizer. /** 3GPP LTE Downlink channel estimator and equalizer.
* Estimates the channel in the resource elements transmitting references and interpolates for the rest * Estimates the channel in the resource elements transmitting references and interpolates for the rest
@ -124,9 +126,13 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
} }
q->smooth_filter_len = 0; q->smooth_filter_len = 0;
#ifdef DEFAULT_FILTER_LEN
set_default_filter(q, DEFAULT_FILTER_LEN);
#else
float fil[3] = {0.1, 0.8, 0.1}; float fil[3] = {0.1, 0.8, 0.1};
srslte_chest_dl_set_smooth_filter(q, fil, 3); srslte_chest_dl_set_smooth_filter(q, fil, 3);
//set_default_filter(q, DEFAULT_FILTER_LEN); #endif
q->cell = cell; q->cell = cell;
} }

@ -82,7 +82,6 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
srslte_chest_dl_t est; srslte_chest_dl_t est;
srslte_precoding_t cheq;
cf_t *input = NULL, *ce = NULL, *h = NULL, *output = NULL; cf_t *input = NULL, *ce = NULL, *h = NULL, *output = NULL;
int i, j, n_port=0, sf_idx=0, cid=0, num_re; int i, j, n_port=0, sf_idx=0, cid=0, num_re;
int ret = -1; int ret = -1;
@ -130,8 +129,6 @@ int main(int argc, char **argv) {
max_cid = cell.id; max_cid = cell.id;
} }
srslte_precoding_init(&cheq, num_re);
while(cid <= max_cid) { while(cid <= max_cid) {
cell.id = cid; cell.id = cid;
if (srslte_chest_dl_init(&est, cell)) { if (srslte_chest_dl_init(&est, cell)) {
@ -227,8 +224,6 @@ int main(int argc, char **argv) {
do_exit: do_exit:
srslte_precoding_free(&cheq);
if (output) { if (output) {
free(output); free(output);
} }

@ -57,7 +57,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
int i; int i;
srslte_cell_t cell; srslte_cell_t cell;
srslte_chest_dl_t chest; srslte_chest_dl_t chest;
srslte_precoding_t cheq;
cf_t *input_signal = NULL, *output_signal[SRSLTE_MAX_LAYERS]; cf_t *input_signal = NULL, *output_signal[SRSLTE_MAX_LAYERS];
cf_t *output_signal2 = NULL; cf_t *output_signal2 = NULL;
cf_t *ce[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS];
@ -114,8 +114,6 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
output_signal2 = srslte_vec_malloc(nof_re * sizeof(cf_t)); output_signal2 = srslte_vec_malloc(nof_re * sizeof(cf_t));
srslte_precoding_init(&cheq, nof_re);
/* Create output values */ /* Create output values */
if (nlhs >= 1) { if (nlhs >= 1) {
plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX); plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX);
@ -161,7 +159,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
if (cell.nof_ports == 1) { if (cell.nof_ports == 1) {
srslte_predecoding_single(input_signal, ce[0], output_signal2, nof_re, srslte_chest_dl_get_noise_estimate(&chest)); srslte_predecoding_single(input_signal, ce[0], output_signal2, nof_re, srslte_chest_dl_get_noise_estimate(&chest));
} else { } else {
srslte_predecoding_diversity(&cheq, input_signal, ce, output_signal, cell.nof_ports, nof_re, srslte_chest_dl_get_noise_estimate(&chest)); srslte_predecoding_diversity(input_signal, ce, output_signal, cell.nof_ports, nof_re);
srslte_layerdemap_diversity(output_signal, output_signal2, cell.nof_ports, nof_re/cell.nof_ports); srslte_layerdemap_diversity(output_signal, output_signal2, cell.nof_ports, nof_re/cell.nof_ports);
} }
@ -205,7 +203,6 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
srslte_chest_dl_free(&chest); srslte_chest_dl_free(&chest);
srslte_precoding_free(&cheq);
return; return;
} }

@ -34,7 +34,6 @@
#include "srslte/common/phy_common.h" #include "srslte/common/phy_common.h"
#include "srslte/common/sequence.h" #include "srslte/common/sequence.h"
#define FORCE_STANDARD_RATE
#ifdef FORCE_STANDARD_RATE #ifdef FORCE_STANDARD_RATE
static bool use_standard_rates = true; static bool use_standard_rates = true;
#else #else

@ -206,8 +206,8 @@ int main(int argc, char **argv) {
} }
srslte_ch_awgn_f(llr, llr, var[i], coded_length); srslte_ch_awgn_f(llr, llr, var[i], coded_length);
srslte_vec_quant_fuc(llr, llr_c, Gain, 127.5, 255, coded_length);
srslte_vec_quant_fuc(llr, llr_c, Gain, 127.5, 255, coded_length);
struct timeval t[3]; struct timeval t[3];
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
@ -264,8 +264,7 @@ int main(int argc, char **argv) {
free(data_rx); free(data_rx);
if (snr_points == 1) { if (snr_points == 1) {
int expected_errors = get_expected_errors(nof_frames, int expected_errors = get_expected_errors(nof_frames, seed, frame_length, tail_biting, ebno_db);
seed, frame_length, tail_biting, ebno_db);
if (expected_errors == -1) { if (expected_errors == -1) {
fprintf(stderr, "Test parameters not defined in test_results.h\n"); fprintf(stderr, "Test parameters not defined in test_results.h\n");
exit(-1); exit(-1);

@ -38,6 +38,7 @@
#include <xmmintrin.h> #include <xmmintrin.h>
#include <pmmintrin.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_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);
#endif #endif
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
@ -53,81 +54,6 @@ int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl
* *
**************************************************/ **************************************************/
int srslte_precoding_init(srslte_precoding_t *q, uint32_t max_frame_len) {
if (q) {
bzero(q, sizeof(srslte_precoding_t));
q->h_mod = srslte_vec_malloc(sizeof(cf_t) * max_frame_len);
if (!q->h_mod) {
perror("malloc");
goto clean_exit;
}
q->tmp1 = srslte_vec_malloc(sizeof(cf_t) * max_frame_len);
if (!q->tmp1) {
perror("malloc");
goto clean_exit;
}
q->tmp2 = srslte_vec_malloc(sizeof(cf_t) * max_frame_len);
if (!q->tmp2) {
perror("malloc");
goto clean_exit;
}
q->tmp3 = srslte_vec_malloc(sizeof(cf_t) * max_frame_len);
if (!q->tmp3) {
perror("malloc");
goto clean_exit;
}
q->y_mod = srslte_vec_malloc(sizeof(float) * max_frame_len);
if (!q->y_mod) {
perror("malloc");
goto clean_exit;
}
q->z_real = srslte_vec_malloc(sizeof(float) * max_frame_len);
if (!q->z_real) {
perror("malloc");
goto clean_exit;
}
q->z_imag = srslte_vec_malloc(sizeof(float) * max_frame_len);
if (!q->z_imag) {
perror("malloc");
goto clean_exit;
}
q->max_frame_len = max_frame_len;
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
clean_exit:
srslte_precoding_free(q);
return SRSLTE_ERROR;
}
void srslte_precoding_free(srslte_precoding_t *q) {
if (q->tmp1) {
free(q->tmp1);
}
if (q->tmp2) {
free(q->tmp2);
}
if (q->tmp3) {
free(q->tmp3);
}
if (q->h_mod) {
free(q->h_mod);
}
if (q->y_mod) {
free(q->y_mod);
}
if (q->z_real) {
free(q->z_real);
}
if (q->z_imag) {
free(q->z_imag);
}
bzero(q, sizeof(srslte_precoding_t));
}
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#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))) #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)))
@ -262,83 +188,37 @@ int srslte_predecoding_single(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float
#endif #endif
} }
/* ZF/MMSE STBC equalizer x=y(H'H+n0·I)^(-1)H' (ZF is n0=0.0) /* 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 srslte_predecoding_diversity(srslte_precoding_t *q, 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 nof_ports, int nof_symbols, float noise_estimate)
{ {
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
cf_t h00, h01, h10, h11, r0, r1;
#define new float hh;
#ifdef new
for (i = symbol_start/2; i < nof_symbols / 2; i++) {
// reuse buffers h00 = h[0][2 * i];
cf_t *r0 = q->tmp3; h01 = h[0][2 * i+1];
cf_t *r1 = &q->tmp3[nof_symbols/2]; h10 = h[1][2 * i];
cf_t *h0 = q->h_mod; h11 = h[1][2 * i+1];
cf_t *h1 = &q->h_mod[nof_symbols/2]; hh = crealf(h00) * crealf(h00) + cimagf(h00) * cimagf(h00)
+ crealf(h11) * crealf(h11) + cimagf(h11) * cimagf(h11);
float *modhh = q->y_mod;
float *modh0 = q->z_real;
float *modh1 = q->z_imag;
// prepare buffers
for (i=0;i<nof_symbols/2;i++) {
h0[i] = h[0][2*i]; // h0
h1[i] = h[1][2*i+1]; // h1
r0[i] = y[2*i]; // r0
r1[i] = y[2*i+1]; // r1
}
// Compute common dividend and store in y_mod
srslte_vec_abs_square_cf(h0, modh0, nof_symbols/2);
srslte_vec_abs_square_cf(h1, modh1, nof_symbols/2);
srslte_vec_sum_fff(modh0, modh1, modhh, nof_symbols/2);
//if (noise_estimate > 0.0) {
// (H'H + n0)
//srslte_vec_sc_add_fff(modhh, noise_estimate, modhh, nof_symbols/2);
//}
srslte_vec_sc_prod_fff(modhh, 1/sqrt(2), modhh, nof_symbols/2);
// x[0] = r0·h0*/(|h0|+|h1|)+r1*·h1/(|h0|+|h1|)
srslte_vec_prod_conj_ccc(r0,h0,q->tmp1, nof_symbols/2);
srslte_vec_prod_conj_ccc(h1,r1,q->tmp2, nof_symbols/2);
srslte_vec_sum_ccc(q->tmp1, q->tmp2, x[0], nof_symbols/2);
srslte_vec_div_cfc(x[0], modhh, x[0], q->z_real, q->z_imag, nof_symbols/2);
// x[1] = r1·h0*/(|h0|+|h1|)-r0*·h1/(|h0|+|h1|)
srslte_vec_prod_conj_ccc(r1,h0,q->tmp1, nof_symbols/2);
srslte_vec_prod_conj_ccc(h1,r0,q->tmp2, nof_symbols/2);
srslte_vec_sub_ccc(q->tmp1, q->tmp2, x[1], nof_symbols/2);
srslte_vec_div_cfc(x[1], modhh, x[1], q->z_real, q->z_imag, nof_symbols/2);
#else
cf_t h0, h1, h2, h3, r0, r1, r2, r3;
float hh, hh02, hh13;
for (i = 0; i < nof_symbols / 2; i++) {
h0 = h[0][2 * i];
h1 = h[1][2 * i];
hh = crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0)
+ crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1) + noise_estimate;
r0 = y[2 * i]; r0 = y[2 * i];
r1 = y[2 * i + 1]; r1 = y[2 * i + 1];
if (hh == 0) { if (hh == 0) {
hh = 1e-2; hh = 1e-4;
} }
x[0][i] = (conjf(h0) * r0 + h1 * conjf(r1)) / hh * sqrt(2); x[0][i] = (conjf(h00) * r0 + h11 * conjf(r1)) / hh * sqrt(2);
x[1][i] = (-h1 * conj(r0) + conj(h0) * r1) / hh * sqrt(2); x[1][i] = (-h10 * conj(r0) + conj(h01) * r1) / hh * sqrt(2);
} }
#endif
return i; return i;
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
cf_t h0, h1, h2, h3, r0, r1, r2, r3; cf_t h0, h1, h2, h3, r0, r1, r2, r3;
float hh02, hh13; float hh02, hh13;
int m_ap = (nof_symbols % 4) ? ((nof_symbols - 2) / 4) : nof_symbols / 4; int m_ap = (nof_symbols % 4) ? ((nof_symbols - 2) / 4) : nof_symbols / 4;
for (i = 0; i < m_ap; i++) { for (i = symbol_start; i < m_ap; i++) {
h0 = h[0][4 * i]; h0 = h[0][4 * i];
h1 = h[1][4 * i + 2]; h1 = h[1][4 * i + 2];
h2 = h[2][4 * i]; h2 = h[2][4 * i];
@ -365,8 +245,88 @@ int srslte_predecoding_diversity(srslte_precoding_t *q, cf_t *y, cf_t *h[SRSLTE_
} }
} }
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);
}
/* 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)
{
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;
__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 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;
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));
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));
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));
/* Compute channel gain */
hhadd = _mm_hadd_ps(_mm_mul_ps(h00, h00), _mm_mul_ps(h11, h11));
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
// 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);
// 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_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));
return nof_symbols;
}
#endif
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)
{
#ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_ports == 2) {
return srslte_predecoding_diversity2_sse(y, h, x, nof_symbols);
} else {
return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols);
}
#else
return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols);
#endif
}
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int srslte_predecoding_type(srslte_precoding_t *q, cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], 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) { int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) {
if (nof_ports > SRSLTE_MAX_PORTS) { if (nof_ports > SRSLTE_MAX_PORTS) {
@ -392,7 +352,7 @@ int srslte_predecoding_type(srslte_precoding_t *q, cf_t *y, cf_t *h[SRSLTE_MAX_P
break; break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return srslte_predecoding_diversity(q, y, h, x, nof_ports, nof_symbols, noise_estimate); return srslte_predecoding_diversity(y, h, x, nof_ports, nof_symbols);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Error number of layers must equal number of ports in transmit diversity\n"); "Error number of layers must equal number of ports in transmit diversity\n");
@ -417,11 +377,11 @@ int srslte_predecoding_type(srslte_precoding_t *q, cf_t *y, cf_t *h[SRSLTE_MAX_P
* *
**************************************************/ **************************************************/
int srslte_precoding_single(srslte_precoding_t *q, cf_t *x, cf_t *y, int nof_symbols) { int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols) {
memcpy(y, x, nof_symbols * sizeof(cf_t)); memcpy(y, x, nof_symbols * sizeof(cf_t));
return nof_symbols; return nof_symbols;
} }
int srslte_precoding_diversity(srslte_precoding_t *q, cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports, int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports,
int nof_symbols) { int nof_symbols) {
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
@ -467,7 +427,7 @@ int srslte_precoding_diversity(srslte_precoding_t *q, cf_t *x[SRSLTE_MAX_LAYERS]
} }
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int srslte_precoding_type(srslte_precoding_t *q, cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers,
int nof_ports, int nof_symbols, srslte_mimo_type_t type) { int nof_ports, int nof_symbols, srslte_mimo_type_t type) {
if (nof_ports > SRSLTE_MAX_PORTS) { if (nof_ports > SRSLTE_MAX_PORTS) {
@ -484,7 +444,7 @@ int srslte_precoding_type(srslte_precoding_t *q, cf_t *x[SRSLTE_MAX_LAYERS], cf_
switch (type) { switch (type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return srslte_precoding_single(q, x[0], y[0], nof_symbols); return srslte_precoding_single(x[0], y[0], nof_symbols);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports\n"); "Number of ports and layers must be 1 for transmission on single antenna ports\n");
@ -493,7 +453,7 @@ int srslte_precoding_type(srslte_precoding_t *q, cf_t *x[SRSLTE_MAX_LAYERS], cf_
break; break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return srslte_precoding_diversity(q, x, y, nof_ports, nof_symbols); return srslte_precoding_diversity(x, y, nof_ports, nof_symbols);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Error number of layers must equal number of ports in transmit diversity\n"); "Error number of layers must equal number of ports in transmit diversity\n");

@ -61,6 +61,8 @@ 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) ADD_TEST(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4)
# MEX file for predecoding and layer demapping test
BuildMex(MEXNAME diversitydecode SOURCES diversitydecode_mex.c LIBRARIES srslte srslte_mex)

@ -0,0 +1,116 @@
/**
*
* \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 HEST prhs[1]
#define NOF_INPUTS 2
void help()
{
mexErrMsgTxt
("[output] = srslte_predecoder(input, hest, nest)\n\n");
}
/* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
cf_t *input = NULL;
cf_t *hest = NULL;
cf_t *output = NULL;
uint32_t nof_symbols = 0;
if (nrhs < NOF_INPUTS) {
help();
return;
}
// Read input symbols
nof_symbols = mexutils_read_cf(INPUT, &input);
if (nof_symbols < 0) {
mexErrMsgTxt("Error reading input\n");
return;
}
// Read channel estimates
uint32_t nof_symbols2 = mexutils_read_cf(HEST, &hest);
if (nof_symbols < 0) {
mexErrMsgTxt("Error reading hest\n");
return;
}
if ((nof_symbols2 % nof_symbols) != 0) {
mexErrMsgTxt("Hest size must be multiple of input size\n");
return;
}
// Calculate number of ports
uint32_t nof_ports = nof_symbols2/nof_symbols;
cf_t *x[8];
cf_t *h[4];
/* Allocate memory */
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols);
int i;
for (i = 0; i < nof_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;
}
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);
}
if (input) {
free(input);
}
if (output) {
free(output);
}
for (i=0;i<8;i++) {
if (x[i]) {
free(x[i]);
}
}
return;
}

@ -81,7 +81,6 @@ int main(int argc, char **argv) {
cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS],
*xr[SRSLTE_MAX_LAYERS]; *xr[SRSLTE_MAX_LAYERS];
srslte_mimo_type_t type; srslte_mimo_type_t type;
srslte_precoding_t precoding;
parse_args(argc, argv); parse_args(argc, argv);
@ -135,13 +134,8 @@ int main(int argc, char **argv) {
} }
} }
if (srslte_precoding_init(&precoding, nof_symbols * nof_layers)) {
fprintf(stderr, "Error initializing precoding\n");
exit(-1);
}
/* precoding */ /* precoding */
if (srslte_precoding_type(&precoding, x, y, nof_layers, nof_ports, nof_symbols, type) < 0) { if (srslte_precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
@ -172,7 +166,7 @@ int main(int argc, char **argv) {
/* predecoding / equalization */ /* predecoding / equalization */
struct timeval t[3]; struct timeval t[3];
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
if (srslte_predecoding_type(&precoding, r[0], h, xr, nof_ports, nof_layers, if (srslte_predecoding_type(r[0], h, xr, nof_ports, nof_layers,
nof_symbols * nof_layers, type, 0) < 0) { nof_symbols * nof_layers, type, 0) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
@ -204,8 +198,6 @@ int main(int argc, char **argv) {
free(r[0]); free(r[0]);
srslte_precoding_free(&precoding);
printf("Ok\n"); printf("Ok\n");
exit(0); exit(0);
} }

@ -151,10 +151,6 @@ int srslte_pbch_init(srslte_pbch_t *q, srslte_cell_t cell) {
q->cell = cell; q->cell = cell;
q->nof_symbols = (SRSLTE_CP_ISNORM(q->cell.cp)) ? PBCH_RE_CP_NORM : PBCH_RE_CP_EXT; q->nof_symbols = (SRSLTE_CP_ISNORM(q->cell.cp)) ? PBCH_RE_CP_NORM : PBCH_RE_CP_EXT;
if (srslte_precoding_init(&q->precoding, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) {
fprintf(stderr, "Error initializing precoding\n");
}
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
goto clean; goto clean;
} }
@ -239,7 +235,6 @@ void srslte_pbch_free(srslte_pbch_t *q) {
if (q->rm_b) { if (q->rm_b) {
free(q->rm_b); free(q->rm_b);
} }
srslte_precoding_free(&q->precoding);
srslte_sequence_free(&q->seq); srslte_sequence_free(&q->seq);
srslte_modem_table_free(&q->mod); srslte_modem_table_free(&q->mod);
srslte_viterbi_free(&q->decoder); srslte_viterbi_free(&q->decoder);
@ -373,8 +368,6 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
uint32_t nof_bits, uint32_t nof_ports) { uint32_t nof_bits, uint32_t nof_ports) {
int j; int j;
DEBUG("Trying to decode PBCH %d bits, %d ports, src: %d, dst: %d, n=%d\n", nof_bits, nof_ports, src, dst, n);
memcpy(&q->temp[dst * nof_bits], &q->llr[src * nof_bits], memcpy(&q->temp[dst * nof_bits], &q->llr[src * nof_bits],
n * nof_bits * sizeof(float)); n * nof_bits * sizeof(float));
@ -392,6 +385,9 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
/* unrate matching */ /* unrate matching */
srslte_rm_conv_rx(q->temp, 4 * nof_bits, q->rm_f, SRSLTE_BCH_ENCODED_LEN); srslte_rm_conv_rx(q->temp, 4 * nof_bits, q->rm_f, SRSLTE_BCH_ENCODED_LEN);
/* Normalize LLR */
srslte_vec_sc_prod_fff(q->rm_f, 1.0/((float) 2*n), q->rm_f, SRSLTE_BCH_ENCODED_LEN);
/* decode */ /* decode */
srslte_viterbi_decode_f(&q->decoder, q->rm_f, q->data, SRSLTE_BCH_PAYLOADCRC_LEN); srslte_viterbi_decode_f(&q->decoder, q->rm_f, q->data, SRSLTE_BCH_PAYLOADCRC_LEN);
@ -471,8 +467,8 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate);
} else { } else {
srslte_predecoding_diversity(&q->precoding, q->symbols[0], q->ce, x, nant, srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant,
q->nof_symbols, noise_estimate); q->nof_symbols);
srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant); srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant);
} }
@ -482,17 +478,14 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* We know they are ordered. * We know they are ordered.
*
* FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous
* calls.
*/ */
for (nb = 0; nb < q->frame_idx && !ret; nb++) { for (nb = 0; nb < q->frame_idx; nb++) {
for (dst = 0; (dst < 4 - nb) && !ret; dst++) { for (dst = 0; (dst < 4 - nb); dst++) {
for (src = 0; src < q->frame_idx - nb && !ret; src++) { for (src = 0; src < q->frame_idx - nb; src++) {
ret = decode_frame(q, src, dst, nb + 1, nof_bits, nant); ret = decode_frame(q, src, dst, nb + 1, nof_bits, nant);
if (ret == 1) { if (ret == 1) {
if (sfn_offset) { if (sfn_offset) {
*sfn_offset = (int) dst - src; *sfn_offset = (int) dst - src + q->frame_idx - 1;
} }
if (nof_tx_ports) { if (nof_tx_ports) {
*nof_tx_ports = nant; *nof_tx_ports = nant;
@ -500,13 +493,15 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
if (bch_payload) { if (bch_payload) {
memcpy(bch_payload, q->data, sizeof(uint8_t) * SRSLTE_BCH_PAYLOAD_LEN); memcpy(bch_payload, q->data, sizeof(uint8_t) * SRSLTE_BCH_PAYLOAD_LEN);
} }
INFO("Decoded PBCH: src=%d, dst=%d, nb=%d, sfn_offset=%d\n", src, dst, nb+1, (int) dst - src + q->frame_idx - 1);
return 1;
} }
} }
} }
} }
} }
nant++; nant++;
} while(nant <= q->cell.nof_ports && !ret); } while(nant <= q->cell.nof_ports);
/* If not found, make room for the next packet of radio frame symbols */ /* If not found, make room for the next packet of radio frame symbols */
if (q->frame_idx == 4) { if (q->frame_idx == 4) {
@ -561,7 +556,7 @@ int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(&q->precoding, x, q->symbols, q->cell.nof_ports, srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports); q->nof_symbols / q->cell.nof_ports);
} else { } else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));

@ -74,10 +74,6 @@ int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t ce
q->regs = regs; q->regs = regs;
q->nof_symbols = PCFICH_RE; q->nof_symbols = PCFICH_RE;
if (srslte_precoding_init(&q->precoding, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) {
fprintf(stderr, "Error initializing precoding\n");
}
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
goto clean; goto clean;
} }
@ -110,7 +106,6 @@ void srslte_pcfich_free(srslte_pcfich_t *q) {
srslte_sequence_free(&q->seq[ns]); srslte_sequence_free(&q->seq[ns]);
} }
srslte_modem_table_free(&q->mod); srslte_modem_table_free(&q->mod);
srslte_precoding_free(&q->precoding);
bzero(q, sizeof(srslte_pcfich_t)); bzero(q, sizeof(srslte_pcfich_t));
} }
@ -194,8 +189,8 @@ int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate);
} else { } else {
srslte_predecoding_diversity(&q->precoding, q->symbols[0], ce_precoding, x, srslte_predecoding_diversity(q->symbols[0], ce_precoding, x,
q->cell.nof_ports, q->nof_symbols, noise_estimate); q->cell.nof_ports, q->nof_symbols);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports); q->nof_symbols / q->cell.nof_ports);
} }
@ -253,7 +248,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(&q->precoding, x, symbols_precoding, q->cell.nof_ports, srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports); q->nof_symbols / q->cell.nof_ports);
} else { } else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));

@ -67,10 +67,6 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell
q->cell = cell; q->cell = cell;
q->regs = regs; q->regs = regs;
if (srslte_precoding_init(&q->precoding, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) {
fprintf(stderr, "Error initializing precoding\n");
}
/* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */
q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72; q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72;
@ -166,7 +162,6 @@ void srslte_pdcch_free(srslte_pdcch_t *q) {
srslte_sequence_free(&q->seq[i]); srslte_sequence_free(&q->seq[i]);
} }
srslte_precoding_free(&q->precoding);
srslte_modem_table_free(&q->mod); srslte_modem_table_free(&q->mod);
srslte_viterbi_free(&q->decoder); srslte_viterbi_free(&q->decoder);
@ -281,6 +276,9 @@ static int dci_decode(srslte_pdcch_t *q, float *e, uint8_t *data, uint32_t E, ui
/* unrate matching */ /* unrate matching */
srslte_rm_conv_rx(e, E, q->rm_f, 3 * (nof_bits + 16)); srslte_rm_conv_rx(e, E, q->rm_f, 3 * (nof_bits + 16));
/* Normalize LLR */
srslte_vec_sc_prod_fff(q->rm_f, (float) 3 * nof_bits/E, q->rm_f, 3*(nof_bits+16));
/* viterbi decoder */ /* viterbi decoder */
srslte_viterbi_decode_f(&q->decoder, q->rm_f, data, nof_bits + 16); srslte_viterbi_decode_f(&q->decoder, q->rm_f, data, nof_bits + 16);
@ -406,7 +404,7 @@ int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLT
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, nof_symbols, noise_estimate); srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, nof_symbols, noise_estimate);
} else { } else {
srslte_predecoding_diversity(&q->precoding, q->symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols, noise_estimate); srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
} }
@ -532,7 +530,7 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols);
srslte_precoding_diversity(&q->precoding, x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
} else { } else {
memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t));
} }

@ -216,11 +216,6 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) {
INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
q->cell.nof_prb, q->max_re); q->cell.nof_prb, q->max_re);
if (srslte_precoding_init(&q->precoding, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) {
fprintf(stderr, "Error initializing precoding\n");
goto clean;
}
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (srslte_modem_table_lte(&q->mod[i], modulations[i])) { if (srslte_modem_table_lte(&q->mod[i], modulations[i])) {
goto clean; goto clean;
@ -295,7 +290,7 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
srslte_modem_table_free(&q->mod[i]); srslte_modem_table_free(&q->mod[i]);
} }
srslte_precoding_free(&q->precoding);
srslte_sch_free(&q->dl_sch); srslte_sch_free(&q->dl_sch);
bzero(q, sizeof(srslte_pdsch_t)); bzero(q, sizeof(srslte_pdsch_t));
@ -409,8 +404,8 @@ int srslte_pdsch_decode_rnti(srslte_pdsch_t *q,
/* no need for layer demapping */ /* 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(q->symbols[0], q->ce[0], q->d, cfg->nbits.nof_re, noise_estimate);
} else { } else {
srslte_predecoding_diversity(&q->precoding, q->symbols[0], q->ce, x, q->cell.nof_ports, srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports,
cfg->nbits.nof_re, noise_estimate); cfg->nbits.nof_re);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports,
cfg->nbits.nof_re / q->cell.nof_ports); cfg->nbits.nof_re / q->cell.nof_ports);
} }
@ -541,7 +536,7 @@ int srslte_pdsch_encode_rnti(srslte_pdsch_t *q,
/* TODO: only diversity supported */ /* TODO: only diversity supported */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, cfg->nbits.nof_re); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, cfg->nbits.nof_re);
srslte_precoding_diversity(&q->precoding, x, q->symbols, q->cell.nof_ports, srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports,
cfg->nbits.nof_re / q->cell.nof_ports); cfg->nbits.nof_re / q->cell.nof_ports);
} else { } else {
memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t)); memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t));

@ -82,10 +82,6 @@ int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell
q->cell = cell; q->cell = cell;
q->regs = regs; q->regs = regs;
if (srslte_precoding_init(&q->precoding, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) {
fprintf(stderr, "Error initializing precoding\n");
}
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) {
goto clean; goto clean;
} }
@ -109,7 +105,6 @@ void srslte_phich_free(srslte_phich_t *q) {
srslte_sequence_free(&q->seq[ns]); srslte_sequence_free(&q->seq[ns]);
} }
srslte_modem_table_free(&q->mod); srslte_modem_table_free(&q->mod);
srslte_precoding_free(&q->precoding);
bzero(q, sizeof(srslte_phich_t)); bzero(q, sizeof(srslte_phich_t));
@ -217,8 +212,8 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_M
/* no need for layer demapping */ /* 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(q->symbols[0], q->ce[0], q->d0, SRSLTE_PHICH_MAX_NSYMB, noise_estimate);
} else { } else {
srslte_predecoding_diversity(&q->precoding, q->symbols[0], ce_precoding, x, srslte_predecoding_diversity(q->symbols[0], ce_precoding, x,
q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB);
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports,
SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
} }
@ -382,7 +377,7 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB);
srslte_precoding_diversity(&q->precoding, x, symbols_precoding, q->cell.nof_ports, srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
/**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */
} else { } else {

@ -218,12 +218,6 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) {
goto clean; goto clean;
} }
/* This is for equalization at receiver */
if (srslte_precoding_init(&q->equalizer, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) {
fprintf(stderr, "Error initializing precoding\n");
goto clean;
}
q->rnti_is_set = false; q->rnti_is_set = false;
// Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission // Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission
@ -281,8 +275,6 @@ void srslte_pusch_free(srslte_pusch_t *q) {
srslte_dft_precoding_free(&q->dft_precoding); srslte_dft_precoding_free(&q->dft_precoding);
srslte_precoding_free(&q->equalizer);
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
srslte_sequence_free(&q->seq[i]); srslte_sequence_free(&q->seq[i]);
} }

@ -50,9 +50,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_pbch_t pbch; srslte_pbch_t pbch;
srslte_chest_dl_t chest; srslte_chest_dl_t chest;
srslte_ofdm_t ofdm_rx; srslte_ofdm_t ofdm_rx;
cf_t *input_fft; cf_t *input_fft = NULL;
cf_t *ce[SRSLTE_MAX_PORTS], *ce_slot[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS], *ce_slot[SRSLTE_MAX_PORTS];
srslte_verbose = SRSLTE_VERBOSE_DEBUG;
if (nrhs < NOF_INPUTS) { if (nrhs < NOF_INPUTS) {
help(); help();
return; return;
@ -78,14 +80,39 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
return; return;
} }
uint32_t nof_ports = cell.nof_ports;
//cell.nof_ports = 0;
if (srslte_pbch_init(&pbch, cell)) { if (srslte_pbch_init(&pbch, cell)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return; return;
} }
cell.nof_ports = nof_ports;
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ce_slot[i] = &ce[i][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
}
int nof_subframes=1;
if (mexutils_isCell(INPUT)) {
nof_subframes = mexutils_getLength(INPUT);
mexPrintf("input is cell. %d subframes\n", nof_subframes);
}
nof_ports = 0;
int sfn_offset = 0;
int n = -1;
for (int s=0;s<nof_subframes;s++) {
mxArray *tmp = (mxArray*) INPUT;
if (mexutils_isCell(INPUT)) {
tmp = mexutils_getCellArray(INPUT, s);
}
// Read input signal // Read input signal
cf_t *input_signal = NULL; cf_t *input_signal = NULL;
int insignal_len = mexutils_read_cf(INPUT, &input_signal); int insignal_len = mexutils_read_cf(tmp, &input_signal);
if (insignal_len < 0) { if (insignal_len < 0) {
mexErrMsgTxt("Error reading input signal\n"); mexErrMsgTxt("Error reading input signal\n");
return; return;
@ -123,14 +150,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
noise_power = srslte_chest_dl_get_noise_estimate(&chest); noise_power = srslte_chest_dl_get_noise_estimate(&chest);
} }
for (int i=0;i<SRSLTE_MAX_PORTS;i++) { n = srslte_pbch_decode(&pbch, &input_fft[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)],
ce_slot[i] = &ce[i][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
}
uint32_t nof_ports;
int n = srslte_pbch_decode(&pbch, &input_fft[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)],
ce_slot, noise_power, ce_slot, noise_power,
NULL, &nof_ports, NULL); NULL, &nof_ports, &sfn_offset);
}
if (nlhs >= 1) { if (nlhs >= 1) {
if (n == 1) { if (n == 1) {
@ -143,7 +166,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexutils_write_cf(pbch.d, &plhs[1], pbch.nof_symbols, 1); mexutils_write_cf(pbch.d, &plhs[1], pbch.nof_symbols, 1);
} }
if (nlhs >= 3) { if (nlhs >= 3) {
mexutils_write_f(pbch.llr, &plhs[2], 2*pbch.nof_symbols, 1); mexutils_write_f(pbch.temp, &plhs[2], 4*2*pbch.nof_symbols, 1);
} }
if (nlhs >= 4) { if (nlhs >= 4) {
mexutils_write_cf(ce[0], &plhs[3], SRSLTE_SF_LEN_RE(cell.nof_prb,cell.cp)/14, 14); mexutils_write_cf(ce[0], &plhs[3], SRSLTE_SF_LEN_RE(cell.nof_prb,cell.cp)/14, 14);
@ -157,6 +180,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
if (nlhs >= 7) { if (nlhs >= 7) {
mexutils_write_cf(pbch.ce[0], &plhs[6], pbch.nof_symbols, 1); mexutils_write_cf(pbch.ce[0], &plhs[6], pbch.nof_symbols, 1);
} }
if (nlhs >= 8) {
plhs[7] = mxCreateDoubleScalar(sfn_offset);
}
if (nlhs >= 9) {
mexutils_write_f(pbch.rm_f, &plhs[8], 120, 1);
}
srslte_chest_dl_free(&chest); srslte_chest_dl_free(&chest);
srslte_ofdm_rx_free(&ofdm_rx); srslte_ofdm_rx_free(&ofdm_rx);
@ -165,8 +194,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
for (i=0;i<cell.nof_ports;i++) { for (i=0;i<cell.nof_ports;i++) {
free(ce[i]); free(ce[i]);
} }
if(input_fft) {
free(input_fft); free(input_fft);
}
return; return;
} }

@ -152,6 +152,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
if (nlhs >= 3) { if (nlhs >= 3) {
mexutils_write_cf(pcfich.symbols[0], &plhs[2], 16, 1); mexutils_write_cf(pcfich.symbols[0], &plhs[2], 16, 1);
} }
if (nlhs >= 4) {
mexutils_write_cf(ce[0], &plhs[3], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1);
}
srslte_chest_dl_free(&chest); srslte_chest_dl_free(&chest);
srslte_ofdm_rx_free(&ofdm_rx); srslte_ofdm_rx_free(&ofdm_rx);

@ -95,7 +95,7 @@ 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 /** 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. * 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) { int rf_mib_decoder(srslte_rf_t *rf, cell_search_cfg_t *config, srslte_cell_t *cell, float *cfo) {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
srslte_ue_mib_sync_t ue_mib; srslte_ue_mib_sync_t ue_mib;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
@ -116,6 +116,11 @@ int rf_mib_decoder(srslte_rf_t *rf, cell_search_cfg_t *config, srslte_cell_t *ce
INFO("Starting receiver...\n", 0); INFO("Starting receiver...\n", 0);
srslte_rf_start_rx_stream(rf); srslte_rf_start_rx_stream(rf);
// Set CFO if available
if (cfo) {
srslte_ue_sync_set_cfo(&ue_mib.ue_sync, *cfo);
}
/* Find and decody MIB */ /* Find and decody MIB */
ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pss, bch_payload, &cell->nof_ports, NULL); ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pss, bch_payload, &cell->nof_ports, NULL);
if (ret < 0) { if (ret < 0) {
@ -131,6 +136,11 @@ int rf_mib_decoder(srslte_rf_t *rf, cell_search_cfg_t *config, srslte_cell_t *ce
config->init_agc = srslte_agc_get_gain(&ue_mib.ue_sync.agc); config->init_agc = srslte_agc_get_gain(&ue_mib.ue_sync.agc);
} }
// Save CFO
if (cfo) {
*cfo = srslte_ue_sync_get_cfo(&ue_mib.ue_sync);
}
clean_exit: clean_exit:
srslte_rf_stop_rx_stream(rf); srslte_rf_stop_rx_stream(rf);
@ -142,7 +152,7 @@ clean_exit:
/** This function is simply a wrapper to the ue_cell_search module for rf devices /** 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 rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config,
int force_N_id_2, srslte_cell_t *cell) int force_N_id_2, srslte_cell_t *cell, float *cfo)
{ {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
srslte_ue_cellsearch_t cs; srslte_ue_cellsearch_t cs;
@ -150,18 +160,14 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config,
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, srslte_rf_recv_wrapper_cs, (void*) rf)) { if (srslte_ue_cellsearch_init(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, (void*) rf)) {
fprintf(stderr, "Error initiating UE cell detect\n"); fprintf(stderr, "Error initiating UE cell detect\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (config->max_frames_pss) { if (config->nof_valid_pss_frames) {
srslte_ue_cellsearch_set_nof_frames_to_scan(&cs, config->max_frames_pss); srslte_ue_cellsearch_set_nof_valid_frames(&cs, config->nof_valid_pss_frames);
} }
if (config->threshold) {
srslte_ue_cellsearch_set_threshold(&cs, config->threshold);
}
if (config->init_agc > 0) { if (config->init_agc > 0) {
srslte_ue_sync_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_th_wrapper, config->init_agc); srslte_ue_sync_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_th_wrapper, config->init_agc);
} }
@ -206,6 +212,11 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config,
cell->cp = found_cells[max_peak_cell].cp; cell->cp = found_cells[max_peak_cell].cp;
} }
// Save CFO
if (cfo) {
*cfo = found_cells[max_peak_cell].cfo;
}
// Save AGC value for MIB decoding // Save AGC value for MIB decoding
if (config->init_agc > 0) { if (config->init_agc > 0) {
config->init_agc = srslte_agc_get_gain(&cs.ue_sync.agc); config->init_agc = srslte_agc_get_gain(&cs.ue_sync.agc);
@ -223,15 +234,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, * 0 if no cell was found or MIB could not be decoded,
* -1 on error * -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) 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 ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
printf("Searching for cell...\n"); printf("Searching for cell...\n");
ret = rf_cell_search(rf, config, force_N_id_2, cell); ret = rf_cell_search(rf, config, force_N_id_2, cell, cfo);
if (ret > 0) { if (ret > 0) {
printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3); printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3);
ret = rf_mib_decoder(rf, config, cell); ret = rf_mib_decoder(rf, config, cell, cfo);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id); fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id);
return SRSLTE_ERROR; return SRSLTE_ERROR;

@ -51,7 +51,9 @@ void srslte_cp_synch_free(srslte_cp_synch_t *q)
uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len) uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len)
{ {
if (max_offset <= q->symbol_sz) { if (max_offset > q->symbol_sz) {
max_offset = q->symbol_sz;
}
for (int i=0;i<max_offset;i++) { for (int i=0;i<max_offset;i++) {
q->corr[i] = 0; q->corr[i] = 0;
cf_t *inputPtr = input; cf_t *inputPtr = input;
@ -63,9 +65,6 @@ uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset,
} }
uint32_t max_idx = srslte_vec_max_abs_ci(q->corr, max_offset); uint32_t max_idx = srslte_vec_max_abs_ci(q->corr, max_offset);
return max_idx; return max_idx;
} else {
return 0;
}
} }
cf_t srslte_cp_synch_corr_output(srslte_cp_synch_t *q, uint32_t offset) cf_t srslte_cp_synch_corr_output(srslte_cp_synch_t *q, uint32_t offset)

@ -70,11 +70,14 @@ static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSL
static void extract_pair_sss(srslte_sss_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { static void extract_pair_sss(srslte_sss_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) {
cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX];
float ce_mod[2*SRSLTE_SSS_N], z_real[2*SRSLTE_SSS_N], z_imag[2*SRSLTE_SSS_N];
srslte_dft_run_c(&q->dftp_input, input, input_fft); srslte_dft_run_c(&q->dftp_input, input, input_fft);
if (ce) { if (ce) {
srslte_vec_prod_conj_ccc(&input_fft[q->fft_size/2-SRSLTE_SSS_N], ce, &input_fft[q->fft_size/2-SRSLTE_SSS_N], 2*SRSLTE_SSS_N); srslte_vec_div_ccc(&input_fft[q->fft_size/2-SRSLTE_SSS_N], ce, ce_mod,
&input_fft[q->fft_size/2-SRSLTE_SSS_N], z_real, z_imag,
2*SRSLTE_SSS_N);
} }
for (int i = 0; i < SRSLTE_SSS_N; i++) { for (int i = 0; i < SRSLTE_SSS_N; i++) {

@ -101,7 +101,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
q->N_id_2 = 10; q->N_id_2 = 10;
q->fft_size = fft_size; q->fft_size = fft_size;
q->frame_size = frame_size; q->frame_size = frame_size;
q->ema_alpha = 0.1; q->ema_alpha = 0.2;
buffer_size = fft_size + frame_size + 1; buffer_size = fft_size + frame_size + 1;

@ -35,9 +35,9 @@
#include "srslte/utils/vector.h" #include "srslte/utils/vector.h"
#include "srslte/sync/cfo.h" #include "srslte/sync/cfo.h"
#define MEANPEAK_EMA_ALPHA 0.2 #define MEANPEAK_EMA_ALPHA 0.1
#define CFO_EMA_ALPHA 0.9 #define CFO_EMA_ALPHA 0.1
#define CP_EMA_ALPHA 0.2 #define CP_EMA_ALPHA 0.1
static bool fft_size_isvalid(uint32_t fft_size) { static bool fft_size_isvalid(uint32_t fft_size) {
if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) {
@ -59,7 +59,6 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
bzero(q, sizeof(srslte_sync_t)); bzero(q, sizeof(srslte_sync_t));
q->detect_cp = true; q->detect_cp = true;
q->mean_peak_value = 0.0;
q->sss_en = true; q->sss_en = true;
q->mean_cfo = 0; q->mean_cfo = 0;
q->N_id_2 = 1000; q->N_id_2 = 1000;
@ -72,7 +71,15 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
q->frame_size = frame_size; q->frame_size = frame_size;
q->max_offset = max_offset; q->max_offset = max_offset;
q->sss_alg = SSS_FULL; q->sss_alg = SSS_FULL;
q->enable_cfo_corr = true; q->enable_cfo_corr = true;
if (srslte_cfo_init(&q->cfocorr, q->frame_size)) {
fprintf(stderr, "Error initiating CFO\n");
goto clean_exit;
}
// Set a CFO tolerance of approx 100 Hz
srslte_cfo_set_tol(&q->cfocorr, 100/(15000*q->fft_size));
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
q->cfo_i_corr[i] = srslte_vec_malloc(sizeof(cf_t)*q->frame_size); q->cfo_i_corr[i] = srslte_vec_malloc(sizeof(cf_t)*q->frame_size);
@ -93,11 +100,6 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
goto clean_exit; goto clean_exit;
} }
if (srslte_cfo_init(&q->cfocorr, frame_size)) {
fprintf(stderr, "Error initiating CFO\n");
goto clean_exit;
}
if (srslte_cp_synch_init(&q->cp_synch, fft_size)) { if (srslte_cp_synch_init(&q->cp_synch, fft_size)) {
fprintf(stderr, "Error initiating CFO\n"); fprintf(stderr, "Error initiating CFO\n");
goto clean_exit; goto clean_exit;
@ -207,7 +209,7 @@ float srslte_sync_get_last_peak_value(srslte_sync_t *q) {
} }
float srslte_sync_get_peak_value(srslte_sync_t *q) { float srslte_sync_get_peak_value(srslte_sync_t *q) {
return q->mean_peak_value; return q->peak_value;
} }
void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) { void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) {
@ -245,34 +247,44 @@ void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) {
*/ */
srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_pos) srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_pos)
{ {
float R_norm, R_ext, C_norm, C_ext; float R_norm=0, R_ext=0, C_norm=0, C_ext=0;
float M_norm=0, M_ext=0; float M_norm=0, M_ext=0;
uint32_t cp_norm_len = SRSLTE_CP_LEN_NORM(7, q->fft_size); uint32_t cp_norm_len = SRSLTE_CP_LEN_NORM(7, q->fft_size);
uint32_t cp_ext_len = SRSLTE_CP_LEN_EXT(q->fft_size); uint32_t cp_ext_len = SRSLTE_CP_LEN_EXT(q->fft_size);
cf_t *input_cp_norm = &input[peak_pos-2*(q->fft_size+cp_norm_len)]; uint32_t nof_symbols = peak_pos/(q->fft_size+cp_ext_len);
cf_t *input_cp_ext = &input[peak_pos-2*(q->fft_size+cp_ext_len)];
for (int i=0;i<2;i++) { if (nof_symbols > 3) {
R_norm = crealf(srslte_vec_dot_prod_conj_ccc(&input_cp_norm[q->fft_size], input_cp_norm, cp_norm_len)); nof_symbols = 3;
C_norm = cp_norm_len * srslte_vec_avg_power_cf(input_cp_norm, cp_norm_len); }
if (nof_symbols > 0) {
cf_t *input_cp_norm = &input[peak_pos-nof_symbols*(q->fft_size+cp_norm_len)];
cf_t *input_cp_ext = &input[peak_pos-nof_symbols*(q->fft_size+cp_ext_len)];
for (int i=0;i<nof_symbols;i++) {
R_norm += crealf(srslte_vec_dot_prod_conj_ccc(&input_cp_norm[q->fft_size], input_cp_norm, cp_norm_len));
C_norm += cp_norm_len * srslte_vec_avg_power_cf(input_cp_norm, cp_norm_len);
input_cp_norm += q->fft_size+cp_norm_len; input_cp_norm += q->fft_size+cp_norm_len;
M_norm += R_norm/C_norm; }
if (C_norm > 0) {
M_norm = R_norm/C_norm;
} }
q->M_norm_avg = SRSLTE_VEC_EMA(M_norm/2, q->M_norm_avg, CP_EMA_ALPHA); q->M_norm_avg = SRSLTE_VEC_EMA(M_norm/nof_symbols, q->M_norm_avg, CP_EMA_ALPHA);
for (int i=0;i<2;i++) { for (int i=0;i<nof_symbols;i++) {
R_ext = crealf(srslte_vec_dot_prod_conj_ccc(&input_cp_ext[q->fft_size], input_cp_ext, cp_ext_len)); R_ext += crealf(srslte_vec_dot_prod_conj_ccc(&input_cp_ext[q->fft_size], input_cp_ext, cp_ext_len));
C_ext = cp_ext_len * srslte_vec_avg_power_cf(input_cp_ext, cp_ext_len); C_ext += cp_ext_len * srslte_vec_avg_power_cf(input_cp_ext, cp_ext_len);
input_cp_ext += q->fft_size+cp_ext_len; input_cp_ext += q->fft_size+cp_ext_len;
if (C_ext > 0) {
M_ext += R_ext/C_ext;
} }
if (C_ext > 0) {
M_ext = R_ext/C_ext;
} }
q->M_ext_avg = SRSLTE_VEC_EMA(M_ext/2, q->M_ext_avg, CP_EMA_ALPHA); q->M_ext_avg = SRSLTE_VEC_EMA(M_ext/nof_symbols, q->M_ext_avg, CP_EMA_ALPHA);
if (q->M_norm_avg > q->M_ext_avg) { if (q->M_norm_avg > q->M_ext_avg) {
return SRSLTE_CP_NORM; return SRSLTE_CP_NORM;
@ -285,6 +297,9 @@ srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_p
return SRSLTE_CP_EXT; return SRSLTE_CP_EXT;
} }
} }
} else {
return SRSLTE_CP_NORM;
}
} }
/* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space /* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space
@ -333,6 +348,44 @@ srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) {
return pss_obj[q->cfo_i+1]; return pss_obj[q->cfo_i+1];
} }
static float cfo_estimate(srslte_sync_t *q, cf_t *input) {
uint32_t cp_offset = 0;
cp_offset = srslte_cp_synch(&q->cp_synch, input, q->max_offset, q->nof_symbols, SRSLTE_CP_LEN_NORM(1,q->fft_size));
cf_t cp_corr_max = srslte_cp_synch_corr_output(&q->cp_synch, cp_offset);
float cfo = -carg(cp_corr_max) / M_PI / 2;
return cfo;
}
static int cfo_i_estimate(srslte_sync_t *q, cf_t *input, int find_offset, int *peak_pos) {
float peak_value;
float max_peak_value = -99;
int max_cfo_i = 0;
srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]};
for (int cfo_i=0;cfo_i<3;cfo_i++) {
srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2);
int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value);
if (peak_value > max_peak_value) {
max_peak_value = peak_value;
if (peak_pos) {
*peak_pos = p;
}
q->peak_value = peak_value;
max_cfo_i = cfo_i-1;
}
}
return max_cfo_i;
}
float srslte_sync_cfo_estimate(srslte_sync_t *q, cf_t *input, int find_offset) {
float cfo_f = cfo_estimate(q, input);
int cfo_i = 0;
if (q->find_cfo_i) {
cfo_i = cfo_i_estimate(q, input, find_offset, NULL);
}
return (float) cfo_i + cfo_f;
}
/** Finds the PSS sequence previously defined by a call to srslte_sync_set_N_id_2() /** Finds the PSS sequence previously defined by a call to srslte_sync_set_N_id_2()
* around the position find_offset in the buffer input. * around the position find_offset in the buffer input.
* Returns 1 if the correlation peak exceeds the threshold set by srslte_sync_set_threshold() * Returns 1 if the correlation peak exceeds the threshold set by srslte_sync_set_threshold()
@ -340,17 +393,17 @@ srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) {
* *
* The maximum of the correlation peak is always stored in *peak_position * The maximum of the correlation peak is always stored in *peak_position
*/ */
int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_position) srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_position)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; srslte_sync_find_ret_t ret = SRSLTE_SYNC_ERROR;
if (q != NULL && if (q != NULL &&
input != NULL && input != NULL &&
srslte_N_id_2_isvalid(q->N_id_2) && srslte_N_id_2_isvalid(q->N_id_2) &&
fft_size_isvalid(q->fft_size)) fft_size_isvalid(q->fft_size))
{ {
int peak_pos; int peak_pos = 0;
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
@ -358,44 +411,20 @@ int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32
*peak_position = 0; *peak_position = 0;
} }
/* Estimate CFO using CP before computing the PSS correlation as in:
* Shoujun Huang, et al, "Joint Time and Frequency Offset Estimation in LTE Downlink"
*/
uint32_t cp_offset = 0;
if (q->enable_cfo_corr) { if (q->enable_cfo_corr) {
cp_offset = srslte_cp_synch(&q->cp_synch, input, q->max_offset, q->nof_symbols, SRSLTE_CP_LEN_NORM(1,q->fft_size)); float cfo = cfo_estimate(q, input);
cf_t cp_corr_max = srslte_cp_synch_corr_output(&q->cp_synch, cp_offset);
float cfo = -carg(cp_corr_max) / M_PI / 2;
/* compute cumulative moving average CFO */ /* compute exponential moving average CFO */
DEBUG("cp_offset_pos=%d, abs=%f, cfo=%f, mean_cfo=%f, nof_symb=%d\n",
cp_offset, cabs(cp_corr_max), cfo, q->mean_cfo, q->nof_symbols);
if (q->mean_cfo) {
q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha); q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha);
} else {
q->mean_cfo = cfo;
}
/* Correct CFO with the averaged CFO estimation */ /* Correct CFO with the averaged CFO estimation */
srslte_cfo_correct(&q->cfocorr, input, input, -q->mean_cfo / q->fft_size); srslte_cfo_correct(&q->cfocorr, input, input, -q->mean_cfo / q->fft_size);
} }
/* If integer CFO is enabled, find max PSS correlation for shifted +1/0/-1 integer versions */ /* If integer CFO is enabled, find max PSS correlation for shifted +1/0/-1 integer versions */
if (q->find_cfo_i && q->enable_cfo_corr) { if (q->find_cfo_i && q->enable_cfo_corr) {
float peak_value; q->cfo_i = cfo_i_estimate(q, input, find_offset, &peak_pos);
float max_peak_value = -99;
peak_pos = 0;
srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]};
for (int cfo_i=0;cfo_i<3;cfo_i++) {
srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2);
int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value);
if (peak_value > max_peak_value) {
max_peak_value = peak_value;
peak_pos = p;
q->peak_value = peak_value;
q->cfo_i = cfo_i-1;
}
}
if (q->cfo_i != 0) { if (q->cfo_i != 0) {
srslte_vec_prod_ccc(input, q->cfo_i_corr[q->cfo_i<0?0:1], input, q->frame_size); srslte_vec_prod_ccc(input, q->cfo_i_corr[q->cfo_i<0?0:1], input, q->frame_size);
INFO("Compensating cfo_i=%d\n", q->cfo_i); INFO("Compensating cfo_i=%d\n", q->cfo_i);
@ -409,8 +438,6 @@ int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32
} }
} }
q->mean_peak_value = SRSLTE_VEC_EMA(q->peak_value, q->mean_peak_value, MEANPEAK_EMA_ALPHA);
if (peak_position) { if (peak_position) {
*peak_position = (uint32_t) peak_pos; *peak_position = (uint32_t) peak_pos;
} }
@ -436,13 +463,16 @@ int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32
} }
} }
// Return 1 (peak detected) even if we couldn't estimate CFO and SSS if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) {
ret = 1; ret = SRSLTE_SYNC_FOUND;
} else {
ret = SRSLTE_SYNC_FOUND_NOSPACE;
}
} else { } else {
ret = 0; ret = SRSLTE_SYNC_NOFOUND;
} }
DEBUG("SYNC ret=%d N_id_2=%d find_offset=%d frame_len=%d, pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n", INFO("SYNC ret=%d N_id_2=%d find_offset=%d frame_len=%d, pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n",
ret, q->N_id_2, find_offset, q->frame_size, peak_pos, q->peak_value, ret, q->N_id_2, find_offset, q->frame_size, peak_pos, q->peak_value,
q->threshold, q->sf_idx, 15*(q->cfo_i+q->mean_cfo)); q->threshold, q->sf_idx, 15*(q->cfo_i+q->mean_cfo));

@ -259,22 +259,22 @@ int main(int argc, char **argv) {
// Find SSS // Find SSS
int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN));
if (sss_idx >= 0 && sss_idx < flen-fft_size) { if (sss_idx >= 0 && sss_idx < flen-fft_size) {
INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1));
srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error2++; sss_error2++;
} }
INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1));
srslte_sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); srslte_sss_synch_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error3++; sss_error3++;
} }
INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1));
}
srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error1++; sss_error1++;
} }
INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1));
}
// Estimate CP // Estimate CP
if (peak_idx > 2*(fft_size + SRSLTE_CP_LEN_EXT(fft_size))) { if (peak_idx > 2*(fft_size + SRSLTE_CP_LEN_EXT(fft_size))) {
@ -300,7 +300,6 @@ int main(int argc, char **argv) {
nof_nodet++; nof_nodet++;
} }
printf("[%5d]: Pos: %5d (%d-%d), PSR: %4.1f (~%4.1f) Pdet: %4.2f, " printf("[%5d]: Pos: %5d (%d-%d), PSR: %4.1f (~%4.1f) Pdet: %4.2f, "
"FA: %4.2f, CFO: %+4.1f KHz, SFO: %+.2f Hz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f%%\r", "FA: %4.2f, CFO: %+4.1f KHz, SFO: %+.2f Hz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f%%\r",
frame_cnt, frame_cnt,
@ -311,7 +310,6 @@ int main(int argc, char **argv) {
(float) sss_error1/nof_det,(float) sss_error2/nof_det,(float) sss_error3/nof_det, (float) sss_error1/nof_det,(float) sss_error2/nof_det,(float) sss_error3/nof_det,
(float) cp_is_norm/nof_det * 100); (float) cp_is_norm/nof_det * 100);
if (frame_cnt > 100) { if (frame_cnt > 100) {
if (abs(last_peak-peak_idx) > 4) { if (abs(last_peak-peak_idx) > 4) {
if (peak_value >= threshold) { if (peak_value >= threshold) {

@ -35,12 +35,7 @@
#include "srslte/utils/debug.h" #include "srslte/utils/debug.h"
#include "srslte/utils/vector.h" #include "srslte/utils/vector.h"
int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), void *stream_handler) int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames,
{
return srslte_ue_cellsearch_init_max(q, SRSLTE_CS_DEFAULT_MAXFRAMES_TOTAL, recv_callback, stream_handler);
}
int srslte_ue_cellsearch_init_max(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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -77,8 +72,7 @@ int srslte_ue_cellsearch_init_max(srslte_ue_cellsearch_t * q, uint32_t max_frame
} }
q->max_frames = max_frames; q->max_frames = max_frames;
q->nof_frames_to_scan = SRSLTE_CS_DEFAULT_NOFFRAMES_TOTAL; q->nof_valid_frames = max_frames;
q->detect_threshold = 1.0;
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
@ -107,15 +101,10 @@ void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t * q)
} }
void srslte_ue_cellsearch_set_threshold(srslte_ue_cellsearch_t * q, float threshold) int srslte_ue_cellsearch_set_nof_valid_frames(srslte_ue_cellsearch_t * q, uint32_t nof_frames)
{
q->detect_threshold = threshold;
}
int srslte_ue_cellsearch_set_nof_frames_to_scan(srslte_ue_cellsearch_t * q, uint32_t nof_frames)
{ {
if (nof_frames <= q->max_frames) { if (nof_frames <= q->max_frames) {
q->nof_frames_to_scan = nof_frames; q->nof_valid_frames = nof_frames;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} else { } else {
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -234,7 +223,6 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q,
/* This means a peak was found and ue_sync is now in tracking state */ /* This means a peak was found and ue_sync is now in tracking state */
ret = srslte_sync_get_cell_id(&q->ue_sync.strack); ret = srslte_sync_get_cell_id(&q->ue_sync.strack);
if (ret >= 0) { if (ret >= 0) {
if (srslte_sync_get_peak_value(&q->ue_sync.strack) > q->detect_threshold) {
/* Save cell id, cp and peak */ /* Save cell id, cp and peak */
q->candidates[nof_detected_frames].cell_id = (uint32_t) ret; q->candidates[nof_detected_frames].cell_id = (uint32_t) ret;
q->candidates[nof_detected_frames].cp = srslte_sync_get_cp(&q->ue_sync.strack); q->candidates[nof_detected_frames].cp = srslte_sync_get_cp(&q->ue_sync.strack);
@ -243,13 +231,11 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q,
q->candidates[nof_detected_frames].cfo = srslte_ue_sync_get_cfo(&q->ue_sync); q->candidates[nof_detected_frames].cfo = srslte_ue_sync_get_cfo(&q->ue_sync);
DEBUG DEBUG
("CELL SEARCH: [%3d/%3d/%d]: Found peak PSR=%.3f, Cell_id: %d CP: %s\n", ("CELL SEARCH: [%3d/%3d/%d]: Found peak PSR=%.3f, Cell_id: %d CP: %s\n",
nof_detected_frames, nof_scanned_frames, q->nof_frames_to_scan, nof_detected_frames, nof_scanned_frames, q->nof_valid_frames,
q->candidates[nof_detected_frames].psr, q->candidates[nof_detected_frames].cell_id, q->candidates[nof_detected_frames].psr, q->candidates[nof_detected_frames].cell_id,
srslte_cp_string(q->candidates[nof_detected_frames].cp)); srslte_cp_string(q->candidates[nof_detected_frames].cp));
nof_detected_frames++; nof_detected_frames++;
}
} }
} else if (ret == 0) { } else if (ret == 0) {
/* This means a peak is not yet found and ue_sync is in find state /* This means a peak is not yet found and ue_sync is in find state
@ -259,7 +245,7 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q,
nof_scanned_frames++; nof_scanned_frames++;
} while (nof_scanned_frames < q->nof_frames_to_scan); } while (nof_scanned_frames < q->max_frames && nof_detected_frames < q->nof_valid_frames);
/* In either case, check if the mean PSR is above the minimum threshold */ /* In either case, check if the mean PSR is above the minimum threshold */
if (nof_detected_frames > 0) { if (nof_detected_frames > 0) {

@ -102,6 +102,8 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
fprintf(stderr, "Error initiating SFO correct\n"); fprintf(stderr, "Error initiating SFO correct\n");
goto clean_exit; goto clean_exit;
} }
srslte_cfo_set_tol(&q->sfo_correct, 0);
q->sf_symbols = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); q->sf_symbols = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t));
if (!q->sf_symbols) { if (!q->sf_symbols) {
perror("malloc"); perror("malloc");

@ -142,7 +142,7 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input,
/* Decode PBCH */ /* Decode PBCH */
ret = srslte_pbch_decode(&q->pbch, &q->sf_symbols[SRSLTE_SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)], ret = srslte_pbch_decode(&q->pbch, &q->sf_symbols[SRSLTE_SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)],
ce_slot1, 0, ce_slot1, srslte_chest_dl_get_noise_estimate(&q->chest),
bch_payload, nof_tx_ports, sfn_offset); bch_payload, nof_tx_ports, sfn_offset);
@ -153,10 +153,11 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input,
srslte_ue_mib_reset(q); srslte_ue_mib_reset(q);
ret = SRSLTE_UE_MIB_FOUND; ret = SRSLTE_UE_MIB_FOUND;
} else { } else {
ret = SRSLTE_UE_MIB_NOTFOUND;
INFO("MIB not decoded: %u\n", q->frame_cnt); INFO("MIB not decoded: %u\n", q->frame_cnt);
q->frame_cnt++; q->frame_cnt++;
ret = SRSLTE_UE_MIB_NOTFOUND;
} }
return ret; return ret;
} }

@ -43,8 +43,8 @@ cf_t dummy[MAX_TIME_OFFSET];
#define TRACK_MAX_LOST 4 #define TRACK_MAX_LOST 4
#define TRACK_FRAME_SIZE 32 #define TRACK_FRAME_SIZE 32
#define FIND_NOF_AVG_FRAMES 2 #define FIND_NOF_AVG_FRAMES 4
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 20 #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 10
#define DEFAULT_SFO_EMA_COEFF 0.1 #define DEFAULT_SFO_EMA_COEFF 0.1
cf_t dummy_offset_buffer[1024*1024]; cf_t dummy_offset_buffer[1024*1024];
@ -171,17 +171,17 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q,
if (cell.id == 1000) { if (cell.id == 1000) {
/* If the cell id is unknown, enable CP detection on find */ /* If the cell id is unknown, enable CP detection on find */
srslte_sync_cp_en(&q->sfind, true); // FIXME: CP detection not working very well. Not supporting Extended CP right now
srslte_sync_cp_en(&q->strack, true); srslte_sync_cp_en(&q->sfind, false);
srslte_sync_cp_en(&q->strack, false);
srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.9); srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.8);
srslte_sync_set_cfo_ema_alpha(&q->strack, 0.4); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1);
srslte_sync_cfo_i_detec_en(&q->sfind, true); srslte_sync_cfo_i_detec_en(&q->sfind, false);
srslte_sync_cfo_i_detec_en(&q->strack, true);
srslte_sync_set_threshold(&q->sfind, 1.5);
q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES;
srslte_sync_set_threshold(&q->sfind, 2.0);
srslte_sync_set_threshold(&q->strack, 1.0); srslte_sync_set_threshold(&q->strack, 1.0);
} else { } else {
@ -192,10 +192,9 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q,
srslte_sync_cp_en(&q->sfind, false); srslte_sync_cp_en(&q->sfind, false);
srslte_sync_cp_en(&q->strack, false); srslte_sync_cp_en(&q->strack, false);
srslte_sync_cfo_i_detec_en(&q->sfind, true); srslte_sync_cfo_i_detec_en(&q->sfind, false);
srslte_sync_cfo_i_detec_en(&q->strack, true);
srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.9); srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.01);
srslte_sync_set_cfo_ema_alpha(&q->strack, 0.01); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.01);
/* In find phase and if the cell is known, do not average pss correlation /* In find phase and if the cell is known, do not average pss correlation
@ -203,10 +202,10 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q,
*/ */
q->nof_avg_find_frames = 1; q->nof_avg_find_frames = 1;
srslte_sync_set_em_alpha(&q->sfind, 1); srslte_sync_set_em_alpha(&q->sfind, 1);
srslte_sync_set_threshold(&q->sfind, 4.0); srslte_sync_set_threshold(&q->sfind, 3.0);
srslte_sync_set_em_alpha(&q->strack, 0.2); srslte_sync_set_em_alpha(&q->strack, 0.2);
srslte_sync_set_threshold(&q->strack, 1.0); srslte_sync_set_threshold(&q->strack, 1.2);
} }
@ -274,6 +273,7 @@ float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) {
} }
void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) { void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) {
srslte_sync_set_cfo(&q->sfind, cfo/15000);
srslte_sync_set_cfo(&q->strack, cfo/15000); srslte_sync_set_cfo(&q->strack, cfo/15000);
} }
@ -346,7 +346,6 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer) {
q->strack.cfo_i = q->sfind.cfo_i; q->strack.cfo_i = q->sfind.cfo_i;
} }
return 0; return 0;
} }
@ -397,7 +396,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) {
} }
q->mean_sfo = SRSLTE_VEC_EMA(q->mean_sample_offset, q->mean_sfo, q->sfo_ema); q->mean_sfo = SRSLTE_VEC_EMA(q->mean_sample_offset, q->mean_sfo, q->sfo_ema);
INFO("\n\nTime offset adjustment: %d samples (%.2f), mean SFO: %.2f Hz, %.5f samples/5-sf, ema=%f, length=%d\n", INFO("Time offset adjustment: %d samples (%.2f), mean SFO: %.2f Hz, %.5f samples/5-sf, ema=%f, length=%d\n",
q->next_rf_sample_offset, q->mean_sample_offset, q->next_rf_sample_offset, q->mean_sample_offset,
srslte_ue_sync_get_sfo(q), srslte_ue_sync_get_sfo(q),
q->mean_sfo, q->sfo_ema, q->sample_offset_correct_period); q->mean_sfo, q->sfo_ema, q->sample_offset_correct_period);
@ -433,6 +432,12 @@ static int track_peak_no(srslte_ue_sync_t *q) {
} else { } else {
INFO("Tracking peak not found. Peak %.3f, %d lost\n", INFO("Tracking peak not found. Peak %.3f, %d lost\n",
srslte_sync_get_last_peak_value(&q->strack), (int) q->frame_no_cnt); srslte_sync_get_last_peak_value(&q->strack), (int) q->frame_no_cnt);
/*
printf("Saving files: pss_corr (%d), input (%d)\n", q->strack.pss.frame_size, SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
srslte_vec_save_file("pss_corr", q->strack.pss.conv_output_avg, q->strack.pss.frame_size*sizeof(float));
srslte_vec_save_file("input", q->input_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)*sizeof(cf_t));
exit(-1);
*/
return 1; return 1;
} }
@ -513,18 +518,27 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
} }
switch (q->state) { switch (q->state) {
case SF_FIND: case SF_FIND:
ret = srslte_sync_find(&q->sfind, input_buffer, 0, &q->peak_idx); switch(srslte_sync_find(&q->sfind, input_buffer, 0, &q->peak_idx)) {
if (ret < 0) { case SRSLTE_SYNC_ERROR:
ret = SRSLTE_ERROR;
fprintf(stderr, "Error finding correlation peak (%d)\n", ret); fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
return SRSLTE_ERROR; return SRSLTE_ERROR;
case SRSLTE_SYNC_FOUND:
ret = find_peak_ok(q, input_buffer);
break;
case SRSLTE_SYNC_FOUND_NOSPACE:
/* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */
q->recv_callback(q->stream, dummy_offset_buffer, q->frame_len/2, NULL);
srslte_sync_reset(&q->sfind);
ret = SRSLTE_SUCCESS;
break;
default:
ret = SRSLTE_SUCCESS;
break;
} }
if (q->do_agc) { if (q->do_agc) {
srslte_agc_process(&q->agc, input_buffer, q->sf_len); srslte_agc_process(&q->agc, input_buffer, q->sf_len);
} }
if (ret == 1) {
ret = find_peak_ok(q, input_buffer);
}
break; break;
case SF_TRACK: case SF_TRACK:
ret = 1; ret = 1;
@ -552,12 +566,26 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
/* Track PSS/SSS around the expected PSS position /* Track PSS/SSS around the expected PSS position
* In tracking phase, the subframe carrying the PSS is always the last one of the frame * In tracking phase, the subframe carrying the PSS is always the last one of the frame
*/ */
ret = srslte_sync_find(&q->strack, input_buffer, switch(srslte_sync_find(&q->strack, input_buffer,
q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2,
&track_idx); &track_idx))
if (ret < 0) { {
case SRSLTE_SYNC_ERROR:
ret = SRSLTE_ERROR;
fprintf(stderr, "Error tracking correlation peak\n"); fprintf(stderr, "Error tracking correlation peak\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
case SRSLTE_SYNC_FOUND:
ret = track_peak_ok(q, track_idx);
break;
case SRSLTE_SYNC_FOUND_NOSPACE:
// It's very very unlikely that we fall here because this event should happen at FIND phase only
ret = 0;
q->state = SF_FIND;
printf("Warning: No space for SSS/CP while in tracking phase\n");
break;
case SRSLTE_SYNC_NOFOUND:
ret = track_peak_no(q);
break;
} }
#ifdef MEASURE_EXEC_TIME #ifdef MEASURE_EXEC_TIME
@ -566,11 +594,6 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
q->mean_exec_time = (float) SRSLTE_VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); q->mean_exec_time = (float) SRSLTE_VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt);
#endif #endif
if (ret == 1) {
ret = track_peak_ok(q, track_idx);
} else {
ret = track_peak_no(q);
}
if (ret == SRSLTE_ERROR) { if (ret == SRSLTE_ERROR) {
fprintf(stderr, "Error processing tracking peak\n"); fprintf(stderr, "Error processing tracking peak\n");
q->state = SF_FIND; q->state = SF_FIND;
@ -579,16 +602,14 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
q->frame_total_cnt++; q->frame_total_cnt++;
} else { } else {
/* Do CFO Correction if not in 0 or 5 subframes */
if (q->correct_cfo) { if (q->correct_cfo) {
srslte_cfo_correct(&q->sfind.cfocorr, srslte_cfo_correct(&q->sfind.cfocorr,
input_buffer, input_buffer,
input_buffer, input_buffer,
-srslte_sync_get_cfo(&q->strack) / q->fft_size); -srslte_sync_get_cfo(&q->sfind) / q->fft_size);
} }
} }
break; break;
} }

@ -704,6 +704,7 @@ uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len) {
void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len) { void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len) {
int i; int i;
int tmp; int tmp;
for (i=0;i<len;i++) { for (i=0;i<len;i++) {
tmp = (int) (offset + gain * in[i]); tmp = (int) (offset + gain * in[i]);
if (tmp < 0) if (tmp < 0)
@ -712,6 +713,5 @@ void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, flo
tmp = clip; tmp = clip;
out[i] = (uint8_t) tmp; out[i] = (uint8_t) tmp;
} }
} }

Loading…
Cancel
Save