diff --git a/matlab/tests/ce b/matlab/tests/ce new file mode 100644 index 000000000..cefc6508e Binary files /dev/null and b/matlab/tests/ce differ diff --git a/matlab/tests/d b/matlab/tests/d new file mode 100644 index 000000000..3ad03af06 Binary files /dev/null and b/matlab/tests/d differ diff --git a/matlab/tests/pdsch_bler.m b/matlab/tests/pdsch_bler.m index 44e0daa65..4efc17348 100644 --- a/matlab/tests/pdsch_bler.m +++ b/matlab/tests/pdsch_bler.m @@ -17,8 +17,6 @@ enbConfig.NDLRB = 100; enbConfig.CFI = 1; enbConfig.DuplexMode='FDD'; -lteCQIDecode - % Transmission mode configuration for PDSCH pdschConfig.NLayers = 1; pdschConfig.TxScheme = 'Port0'; diff --git a/matlab/tests/pdsch_bler_equal.m b/matlab/tests/pdsch_equal.m similarity index 100% rename from matlab/tests/pdsch_bler_equal.m rename to matlab/tests/pdsch_equal.m diff --git a/matlab/tests/pusch_bler.m b/matlab/tests/pusch_bler.m new file mode 100644 index 000000000..68e29d434 --- /dev/null +++ b/matlab/tests/pusch_bler.m @@ -0,0 +1,188 @@ +%% Plot PUSCH BLER vs SNR for PUSCH without equalization +clear +transportBlkSize=904; +modulation='64QAM'; +rvValues=0; +SNR=linspace(-5,0.0,8); +Nblocks=30; + +addpath('../../build/srslte/lib/phch/test') + +% Subframe configuration +ueConfig.NCellID = 100; +ueConfig.CyclicPrefixUL = 'Normal'; +ueConfig.NSubframe = 0; +ueConfig.NULRB = 6; +ueConfig.Shortened = 0; +ueConfig.NTxAnts = 1; +ueConfig.RNTI = 1; +ueConfig.DuplexMode='FDD'; +ueConfig.Hopping = 'Off'; +ueConfig.SeqGroup = 0; +ueConfig.CyclicShift = 0; +ueConfig.Shortened = 0; + +% Transmission mode configuration for PUSCH +puschConfig.NLayers = 1; +puschConfig.TxScheme = 'Port0'; +puschConfig.Modulation = modulation; +puschConfig.NTurboDecIts = 5; +puschConfig.PRBSet = (0:ueConfig.NULRB-1)'; +puschConfig.NBundled = 0; + +% Configure control channels +puschConfig.OCQI = 0; +puschConfig.ORI = 0; +puschConfig.OACK = 0; + +puschConfig.BetaCQI = 2; +puschConfig.BetaRI = 3; +puschConfig.BetaACK = 1; + +info=lteULSCHInfo(ueConfig,puschConfig,transportBlkSize,puschConfig.OCQI,puschConfig.ORI,puschConfig.OACK); +puschConfig.QdACK=info.QdACK; +puschConfig.QdRI=info.QdRI; +puschConfig.QdCQI=info.QdCQI; + +switch (modulation) + case 'QPSK' + bitsPerSym = 2; + case '16QAM' + bitsPerSym = 4; + case '64QAM' + bitsPerSym = 6; +end + +noiseVarfactor = sqrt(2*bitsPerSym); +snr = 10.^(SNR/10); + +nErrors_mat = zeros(length(SNR),length(rvValues)); +nErrorsCtrl_mat = zeros(length(SNR),3); +nErrors_srs = zeros(length(SNR),length(rvValues)); +nErrorsCtrl_srs = zeros(length(SNR),3); + +for k = 1:length(SNR); + subframe=cell(length(rvValues)); + puschIdx=ltePUSCHIndices(ueConfig,puschConfig); + for i=1:length(rvValues) + subframe{i} = lteULResourceGrid(ueConfig); + end + blkCounter = 0; + for l = 1:Nblocks; + % UL-SCH data bits + ulschBits = randi([0 1],transportBlkSize,1); + softBuffer = {}; + + % Control bits + cqi = randi([0 1], puschConfig.OCQI,1); + ri = randi([0 1], puschConfig.ORI,1); + ack = randi([0 1], puschConfig.OACK,1); + + for rvIndex = 1:length(rvValues) + % ULSCH transport channel + puschConfig.RV = rvValues(rvIndex); + puschPayload = lteULSCH(ueConfig, puschConfig, ulschBits, cqi, ri, ack); + + % PUSCH modulated symbols + puschSymbols = ltePUSCH(ueConfig, puschConfig, puschPayload); + puschSize = size(puschSymbols); + + % Addition of noise + noise = (1/noiseVarfactor)*sqrt(1/snr(k))*complex(randn(puschSize),randn(puschSize)); + noisySymbols = puschSymbols + noise; + + subframe{rvIndex}(puschIdx)=noisySymbols; + + % PUSCH Rx-side + [rxCW, puschSymbolsRx] = ltePUSCHDecode(ueConfig, puschConfig, noisySymbols); + if (iscell(rxCW)) + rxCW_=rxCW{1}; + else + rxCW_=rxCW; + end + + % UL-SCH turbo decoding + [rxBits, blkCRCerr, softBuffer,ccqi,cri,cack] = lteULSCHDecode2(ueConfig, puschConfig, ... + transportBlkSize, rxCW_, softBuffer); + + % Add errors to previous error counts + nErrors_mat(k,rvIndex) = nErrors_mat(k,rvIndex)+blkCRCerr; + + if (rvIndex==1) + ack_rx=lteACKDecode(puschConfig,cack); + ri_rx=lteRIDecode(puschConfig,cri); + cqi_rx=lteCQIDecode(puschConfig,ccqi); + + nErrorsCtrl_mat(k,1) = nErrorsCtrl_mat(k,1)+(sum(ack_rx~=ack)>0); + nErrorsCtrl_mat(k,2) = nErrorsCtrl_mat(k,2)+(sum(ri_rx~=ri)>0); + nErrorsCtrl_mat(k,3) = nErrorsCtrl_mat(k,3)+(sum(cqi_rx~=cqi)>0); + end + end + + % Same with srsLTE + [okSRSLTE, cqi_rx_srs, ri_rx_srs, ack_rx_srs] = srslte_pusch(ueConfig, puschConfig, ... + transportBlkSize, subframe, ones(size(subframe{1})), 0); + + nErrors_srs(k,rvIndex) = nErrors_srs(k,rvIndex)+~okSRSLTE; + + if (rvIndex==1) + nErrorsCtrl_srs(k,1) = nErrorsCtrl_srs(k,1)+(sum(ack_rx_srs~=ack)>0); + nErrorsCtrl_srs(k,2) = nErrorsCtrl_srs(k,2)+(sum(ri_rx_srs~=ri)>0); + nErrorsCtrl_srs(k,3) = nErrorsCtrl_srs(k,3)+(sum(cqi_rx_srs~=cqi)>0); + end + end + fprintf('SNR=%.1f dB, BLER_mat=%.2f, BLER_srs=%.2f, BLER_ack=%.2f/%.2f, BLER_ri=%.2f/%.2f, BLER_cqi=%.2f/%.2f\n',... + SNR(k),nErrors_mat(k,rvIndex)/Nblocks, nErrors_srs(k,rvIndex)/Nblocks, ... + nErrorsCtrl_mat(k,1)/Nblocks, nErrorsCtrl_srs(k,1)/Nblocks, ... + nErrorsCtrl_mat(k,3)/Nblocks, nErrorsCtrl_srs(k,2)/Nblocks, ... + nErrorsCtrl_mat(k,2)/Nblocks, nErrorsCtrl_srs(k,3)/Nblocks); +end + +puschBLER_mat = nErrors_mat./Nblocks; +puschBLER_mat(puschBLER_mat==0)=10^-10; + +puschBLER_srs = nErrors_srs./Nblocks; +puschBLER_srs(puschBLER_srs==0)=10^-10; + + +puschCtrlBLER_mat = nErrorsCtrl_mat./Nblocks; +puschCtrlBLER_mat(puschCtrlBLER_mat==0)=10^-10; + +puschCtrlBLER_srs = nErrorsCtrl_srs./Nblocks; +puschCtrlBLER_srs(puschCtrlBLER_srs==0)=10^-10; + +if (Nblocks == 1 && length(SNR) == 1) +else + + ctrlplot=1; + if (puschConfig.OCQI+puschConfig.ORI+puschConfig.OACK>0) + ctrlplot=2; + end + + subplot(ctrlplot,1,1) + semilogy(SNR,puschBLER_mat,SNR,puschBLER_srs); + grid on + xlabel('Eb/No (dB)') + ylabel('BLER') + leg=[]; + for rvIndex = 1:length(rvValues) + leg=strvcat(leg,sprintf('Matlab rv=%d',rvValues(rvIndex))); + end + for rvIndex = 1:length(rvValues) + leg=strvcat(leg,sprintf('srsLTE rv=%d',rvValues(rvIndex))); + end + axis([min(SNR) max(SNR) 10^-4 1]) + + if (ctrlplot==2) + subplot(2,1,2) + semilogy(SNR,puschCtrlBLER_mat,SNR,puschCtrlBLER_srs) + grid on + xlabel('Eb/No (dB)') + ylabel('BLER') + leg=[]; + leg=strvcat(leg,'Matlab ACK','Matlab RI', 'Matlab CQI'); + leg=strvcat(leg,'srsLTE ACK','srsLTE RI', 'srsLTE CQI'); + legend(leg); + axis([min(SNR) max(SNR) 10^-4 1]) + end +end diff --git a/matlab/tests/pusch_test.m b/matlab/tests/pusch_encode_test.m similarity index 74% rename from matlab/tests/pusch_test.m rename to matlab/tests/pusch_encode_test.m index 9bfac1dfb..13a94a7b5 100644 --- a/matlab/tests/pusch_test.m +++ b/matlab/tests/pusch_encode_test.m @@ -1,12 +1,12 @@ -ueConfig=struct('NCellID',1,'NULRB',50,'CyclicPrefixUL','Normal','NTxAnts',1,'RNTI',64); +ueConfig=struct('NCellID',1,'NULRB',6,'CyclicPrefixUL','Normal','NTxAnts',1,'RNTI',64); puschConfig=struct('NLayers',1,'OrthCover','Off','Shortened',0,'NBundled',0); -addpath('/home/ismael/work/srsLTE/debug/srslte/lib/phch/test') +addpath('../../build//srslte/lib/phch/test') -cqilen=[0 20]; +cqilen=[0 4 20]; mods={'64QAM'}; rvs=0; -betas=[0 2.0 2.5 5.0, 20.0]; +betas=[0 5.0, 20.0]; for p=1:ueConfig.NULRB for i=0:26 for m=1:length(mods) @@ -40,7 +40,6 @@ for p=1:ueConfig.NULRB ack_bit=[]; end - if (cqilen(c)>0 || TBs>0) [enc, info]=lteULSCH(ueConfig,puschConfig,trblkin,ones(1,cqilen(c)),ri_bit,ack_bit); cw_mat=ltePUSCH(ueConfig,puschConfig,enc); @@ -49,16 +48,11 @@ for p=1:ueConfig.NULRB %drs_idx=ltePUSCHDRSIndices(ueConfig,puschConfig); subframe_mat = lteULResourceGrid(ueConfig); subframe_mat(idx)=cw_mat; - %subframe_mat(drs_idx)=drs; - waveform = lteSCFDMAModulate(ueConfig,subframe_mat,0); - [waveform_lib, subframe_lib, cwlib, bits]=srslte_pusch_encode(ueConfig,puschConfig,trblkin,ones(1,cqilen(c)),ri_bit,ack_bit); - err=max(abs(waveform-waveform_lib)); + [~, subframe_lib, cwlib, bits]=srslte_pusch_encode(ueConfig,puschConfig,trblkin,ones(1,cqilen(c)),ri_bit,ack_bit); + err=max(abs(subframe_mat(:)-subframe_lib)); if (err > 10^-5) - disp(err) - t=1:200; - %plot(t,bits(t),t,cw_scram(t)) - plot(abs(double(bits)-double(cw_scram))) + plot(abs(subframe_mat(:)-subframe_lib)) error('Error!'); end end diff --git a/matlab/tests/sf_symbols b/matlab/tests/sf_symbols new file mode 100644 index 000000000..c18c441e4 Binary files /dev/null and b/matlab/tests/sf_symbols differ diff --git a/matlab/tests/z b/matlab/tests/z new file mode 100644 index 000000000..3ad03af06 Binary files /dev/null and b/matlab/tests/z differ diff --git a/srslte/lib/phch/prach.c b/srslte/lib/phch/prach.c index af9f71f59..e820fa8b8 100644 --- a/srslte/lib/phch/prach.c +++ b/srslte/lib/phch/prach.c @@ -470,7 +470,7 @@ int srslte_prach_detect(srslte_prach_t *p, indices != NULL) { if(sig_len != p->N_ifft_prach){ - INFO("srslte_prach_detect: Signal is not of length %d", p->N_ifft_prach); + fprintf(stderr, "srslte_prach_detect: Signal is not of length %d", p->N_ifft_prach); return SRSLTE_ERROR_INVALID_INPUTS; } diff --git a/srslte/lib/phch/pusch.c b/srslte/lib/phch/pusch.c index 9bd5ce200..322fe4475 100644 --- a/srslte/lib/phch/pusch.c +++ b/srslte/lib/phch/pusch.c @@ -553,10 +553,10 @@ int srslte_pusch_uci_decode(srslte_pusch_t *q, // Equalization srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate); - + // DFT predecoding srslte_dft_predecoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); - + // Soft demodulation srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); diff --git a/srslte/lib/phch/test/CMakeLists.txt b/srslte/lib/phch/test/CMakeLists.txt index ea1d14aca..6f9653f85 100644 --- a/srslte/lib/phch/test/CMakeLists.txt +++ b/srslte/lib/phch/test/CMakeLists.txt @@ -133,6 +133,7 @@ target_link_libraries(pusch_test srslte) BuildMex(MEXNAME ulsch_encode SOURCES ulsch_encode_test_mex.c LIBRARIES srslte_static srslte_mex) BuildMex(MEXNAME pusch_encode SOURCES pusch_encode_test_mex.c LIBRARIES srslte_static srslte_mex) +BuildMex(MEXNAME pusch SOURCES pusch_test_mex.c LIBRARIES srslte_static srslte_mex) add_test(pusch_test pusch_test) @@ -191,6 +192,7 @@ add_test(prach_test_multi_n4 prach_test_multi -n 4) BuildMex(MEXNAME prach SOURCES prach_test_mex.c LIBRARIES srslte_static srslte_mex) +BuildMex(MEXNAME prach_detect SOURCES prach_detect_test_mex.c LIBRARIES srslte_static srslte_mex) if(UHD_FOUND) diff --git a/srslte/lib/phch/test/prach_detect_test_mex.c b/srslte/lib/phch/test/prach_detect_test_mex.c new file mode 100644 index 000000000..49a45fc99 --- /dev/null +++ b/srslte/lib/phch/test/prach_detect_test_mex.c @@ -0,0 +1,113 @@ +/** + * + * \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 +#define FORCE_POWER2_FFT +#include "srslte/srslte.h" +#include "srslte/mex/mexutils.h" + +/** MEX function to be called from MATLAB to test the channel estimator + */ + +#define UECFG prhs[0] +#define PRACHCFG prhs[1] +#define INPUT prhs[2] +#define NOF_INPUTS 3 + +void help() +{ + mexErrMsgTxt + ("[preamble, offset] = srslte_prach(ueConfig, prachConfig, signal)\n\n"); +} + +/* the gateway function */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + + if (nrhs != NOF_INPUTS) { + help(); + return; + } + + uint32_t n_ul_rb = 0; + if (mexutils_read_uint32_struct(UECFG, "NULRB", &n_ul_rb)) { + mexErrMsgTxt("Field NULRB not found in UE config\n"); + return; + } + int r = srslte_symbol_sz(n_ul_rb); + if (r < 0) { + mexErrMsgTxt("Invalid NULRB\n"); + return; + } + uint32_t N_ifft_ul = (uint32_t) r; + + uint32_t sf_idx = 0; + mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx); + uint32_t nframe = 0; + mexutils_read_uint32_struct(UECFG, "NFrame", &nframe); + + uint32_t preamble_format = 0; + mexutils_read_uint32_struct(PRACHCFG, "Format", &preamble_format); + uint32_t root_seq_idx = 0; + mexutils_read_uint32_struct(PRACHCFG, "SeqIdx", &root_seq_idx); + uint32_t seq_idx = 0; + mexutils_read_uint32_struct(PRACHCFG, "PreambleIdx", &seq_idx); + uint32_t zero_corr_zone = 0; + mexutils_read_uint32_struct(PRACHCFG, "CyclicShiftIdx", &zero_corr_zone); + uint32_t high_speed_flag = 0; + mexutils_read_uint32_struct(PRACHCFG, "HighSpeed", &high_speed_flag); + uint32_t timing_offset = 0; + mexutils_read_uint32_struct(PRACHCFG, "TimingOffset", &timing_offset); + uint32_t frequency_offset = 0; + mexutils_read_uint32_struct(PRACHCFG, "FreqOffset", &frequency_offset); + + srslte_prach_t prach; + if (srslte_prach_init(&prach, N_ifft_ul, preamble_format, root_seq_idx, high_speed_flag, zero_corr_zone)) { + mexErrMsgTxt("Error initiating PRACH\n"); + return; + } + + cf_t *input_signal = NULL; + int nof_samples = mexutils_read_cf(INPUT, &input_signal); + + uint32_t preambles[64]; + uint32_t nof_detected = 0; + mexPrintf("nof_samples=%d\n", nof_samples); + if (srslte_prach_detect(&prach, frequency_offset, input_signal, nof_samples, preambles, &nof_detected)) { + mexErrMsgTxt("Error detecting PRACH\n"); + return; + } + + if (nlhs >= 1) { + mexutils_write_int((int*) preambles, &plhs[0], nof_detected, 1); + } + + free(input_signal); + srslte_prach_free(&prach); + + return; +} + diff --git a/srslte/lib/phch/test/pusch_encode_test_mex.c b/srslte/lib/phch/test/pusch_encode_test_mex.c index 0e9a0d7f2..02bf3ecd7 100644 --- a/srslte/lib/phch/test/pusch_encode_test_mex.c +++ b/srslte/lib/phch/test/pusch_encode_test_mex.c @@ -101,7 +101,6 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexErrMsgTxt("Unknown modulation\n"); return; } - mxFree(mod_str); float *prbset = NULL; @@ -135,20 +134,18 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) grant.Qm = srslte_mod_bits_x_symbol(grant.mcs.mod); if (srslte_pusch_cfg(&pusch, &cfg, &grant, NULL, NULL, NULL, cfg.sf_idx, cfg.rv, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); + fprintf(stderr, "Error configuring PUSCH\n"); exit(-1); } mexPrintf("L_prb: %d, n_prb: %d\n", grant.L_prb, grant.n_prb[0]); - srslte_softbuffer_tx_t softbuffer; if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { mexErrMsgTxt("Error initiating soft buffer\n"); return; } - uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp); cf_t *sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re); if (!sf_symbols) { @@ -215,19 +212,23 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } } - cf_t *scfdma = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - bzero(scfdma, sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - srslte_ofdm_t fft; - srslte_ofdm_tx_init(&fft, SRSLTE_CP_NORM, cell.nof_prb); - srslte_ofdm_set_normalize(&fft, true); - srslte_ofdm_set_freq_shift(&fft, 0.5); - srslte_ofdm_tx_sf(&fft, sf_symbols, scfdma); - // Matlab toolbox expects further normalization - srslte_vec_sc_prod_cfc(scfdma, 1.0/sqrtf(srslte_symbol_sz(cell.nof_prb)), scfdma, SRSLTE_SF_LEN_PRB(cell.nof_prb)); - if (nlhs >= 1) { + + cf_t *scfdma = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + bzero(scfdma, sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + srslte_ofdm_t fft; + srslte_ofdm_tx_init(&fft, SRSLTE_CP_NORM, cell.nof_prb); + srslte_ofdm_set_normalize(&fft, true); + srslte_ofdm_set_freq_shift(&fft, 0.5); + srslte_ofdm_tx_sf(&fft, sf_symbols, scfdma); + // Matlab toolbox expects further normalization + srslte_vec_sc_prod_cfc(scfdma, 1.0/sqrtf(srslte_symbol_sz(cell.nof_prb)), scfdma, SRSLTE_SF_LEN_PRB(cell.nof_prb)); + mexutils_write_cf(scfdma, &plhs[0], SRSLTE_SF_LEN_PRB(cell.nof_prb), 1); + + free(scfdma); + } if (nlhs >= 2) { mexutils_write_cf(sf_symbols, &plhs[1], nof_re, 1); @@ -238,10 +239,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if (nlhs >= 4) { mexutils_write_uint8(pusch.q, &plhs[3], cfg.nbits.nof_bits, 1); } - srslte_pusch_free(&pusch); + srslte_pusch_free(&pusch); + srslte_softbuffer_tx_free(&softbuffer); free(trblkin); free(sf_symbols); - free(scfdma); return; } diff --git a/srslte/lib/phch/test/pusch_test_mex.c b/srslte/lib/phch/test/pusch_test_mex.c new file mode 100644 index 000000000..92589e5e5 --- /dev/null +++ b/srslte/lib/phch/test/pusch_test_mex.c @@ -0,0 +1,308 @@ +/** + * + * \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 +#include "srslte/srslte.h" +#include "srslte/mex/mexutils.h" + +/** MEX function to be called from MATLAB to test the channel estimator + */ + +#define UECFG prhs[0] +#define PUSCHCFG prhs[1] +#define TBS prhs[2] +#define INPUT prhs[3] +#define NOF_INPUTS 4 + +void help() +{ + mexErrMsgTxt + ("[decoded_ok, cqi_data, ri_data, ack_data] = srslte_pusch(ueConfig, puschConfig, trblklen, rxWaveform)\n\n"); +} + +extern int indices[2048]; + +int rv_seq[4] = {0, 2, 3, 1}; + +/* the gateway function */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + srslte_ofdm_t ofdm_tx; + srslte_pusch_t pusch; + srslte_chest_ul_t chest; + cf_t *input_fft; + srslte_softbuffer_rx_t softbuffer; + uint32_t rnti32; + + if (nrhs < NOF_INPUTS) { + help(); + return; + } + + srslte_verbose = SRSLTE_VERBOSE_INFO; + + srslte_cell_t cell; + bzero(&cell, sizeof(srslte_cell_t)); + cell.nof_ports = 1; + if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { + mexErrMsgTxt("Field NCellID not found in UE config\n"); + return; + } + if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { + mexErrMsgTxt("Field NULRB not found in UE config\n"); + return; + } + + srslte_pusch_cfg_t cfg; + bzero(&cfg, sizeof(srslte_pusch_cfg_t)); + if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti32)) { + mexErrMsgTxt("Field RNTI not found in pdsch config\n"); + return; + } + + if (mexutils_read_uint32_struct(UECFG, "NSubframe", &cfg.sf_idx)) { + help(); + return; + } + + if (srslte_ofdm_rx_init(&ofdm_tx, cell.cp, cell.nof_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + return; + } + srslte_ofdm_set_normalize(&ofdm_tx, true); + srslte_ofdm_set_freq_shift(&ofdm_tx, 0.5); + + if (srslte_pusch_init(&pusch, cell)) { + mexErrMsgTxt("Error initiating PDSCH\n"); + return; + } + srslte_pusch_set_rnti(&pusch, (uint16_t) (rnti32 & 0xffff)); + + if (srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb)) { + mexErrMsgTxt("Error initiating soft buffer\n"); + return; + } + + if (srslte_chest_ul_init(&chest, cell)) { + mexErrMsgTxt("Error initializing equalizer\n"); + return; + } + + srslte_ra_ul_grant_t grant; + bzero(&grant, sizeof(srslte_ra_ul_grant_t)); + + char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); + if (!strcmp(mod_str, "QPSK")) { + grant.mcs.mod = SRSLTE_MOD_QPSK; + } else if (!strcmp(mod_str, "16QAM")) { + grant.mcs.mod = SRSLTE_MOD_16QAM; + } else if (!strcmp(mod_str, "64QAM")) { + grant.mcs.mod = SRSLTE_MOD_64QAM; + } else { + mexErrMsgTxt("Unknown modulation\n"); + return; + } + mxFree(mod_str); + + grant.mcs.tbs = mxGetScalar(TBS); + if (grant.mcs.tbs == 0) { + mexErrMsgTxt("Error trblklen is zero\n"); + return; + } + + uint32_t N_srs = 0; + mexutils_read_uint32_struct(PUSCHCFG, "Shortened", &N_srs); + if (N_srs == 1) { + pusch.shortened = true; + } + + float *prbset = NULL; + mxArray *p; + p = mxGetField(PUSCHCFG, 0, "PRBSet"); + if (!p) { + mexErrMsgTxt("Error field PRBSet not found\n"); + return; + } + + grant.L_prb = mexutils_read_f(p, &prbset); + grant.n_prb[0] = prbset[0]; + grant.n_prb[1] = prbset[0]; + free(prbset); + + grant.M_sc = grant.L_prb*SRSLTE_NRE; + grant.M_sc_init = grant.M_sc; // FIXME: What should M_sc_init be? + grant.Qm = srslte_mod_bits_x_symbol(grant.mcs.mod); + + if (srslte_cbsegm(&cfg.cb_segm, grant.mcs.tbs)) { + mexErrMsgTxt("Error computing CB segmentation\n"); + return; + } + + if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &cfg.rv)) { + mexErrMsgTxt("Field RV not found in pdsch config\n"); + return; + } + + uint32_t max_iterations = 5; + mexutils_read_uint32_struct(PUSCHCFG, "NTurboDecIts", &max_iterations); + + /* Configure rest of pdsch_cfg parameters */ + if (srslte_pusch_cfg(&pusch, &cfg, &grant, NULL, NULL, NULL, cfg.sf_idx, cfg.rv, 0)) { + fprintf(stderr, "Error configuring PDSCH\n"); + exit(-1); + } + + srslte_uci_data_t uci_data; + bzero(&uci_data, sizeof(srslte_uci_data_t)); + + mexutils_read_uint32_struct(PUSCHCFG, "OCQI", &uci_data.uci_cqi_len); + mexutils_read_uint32_struct(PUSCHCFG, "ORI", &uci_data.uci_ri_len); + mexutils_read_uint32_struct(PUSCHCFG, "OACK", &uci_data.uci_ack_len); + + float beta; + if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &beta)) { + cfg.uci_cfg.I_offset_cqi = 7; + } else { + cfg.uci_cfg.I_offset_cqi = srslte_sch_find_Ioffset_cqi(beta); + } + if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &beta)) { + cfg.uci_cfg.I_offset_ri = 2; + } else { + cfg.uci_cfg.I_offset_ri = srslte_sch_find_Ioffset_ri(beta); + } + if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &beta)) { + cfg.uci_cfg.I_offset_ack = 0; + } else { + cfg.uci_cfg.I_offset_ack = srslte_sch_find_Ioffset_ack(beta); + } + mexPrintf("TRBL_len: %d, CQI_len: %2d, ACK_len: %d (%d), RI_len: %d (%d)\n", grant.mcs.tbs, + uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ack, uci_data.uci_ri_len, uci_data.uci_ri); + + mexPrintf("I_cqi: %2d, I_ri: %2d, I_ack=%2d\n", cfg.uci_cfg.I_offset_cqi, cfg.uci_cfg.I_offset_ri, cfg.uci_cfg.I_offset_ack); + + + mexPrintf("L_prb: %d, n_prb: %d/%d, TBS=%d\n", grant.L_prb, grant.n_prb[0], grant.n_prb[1], grant.mcs.tbs); + + /** Allocate input buffers */ + int nof_retx=1; + if (mexutils_isCell(INPUT)) { + nof_retx = mexutils_getLength(INPUT); + } + + cf_t *ce = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));; + + uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8); + if (!data_bytes) { + return; + } + srslte_sch_set_max_noi(&pusch.dl_sch, max_iterations); + + input_fft = NULL; + int r=-1; + for (int rvIdx=0;rvIdx 1) { + cfg.rv = rv_seq[rvIdx%4]; + } + } + + // Read input signal + cf_t *input_signal = NULL; + int insignal_len = mexutils_read_cf(tmp, &input_signal); + if (insignal_len < 0) { + mexErrMsgTxt("Error reading input signal\n"); + return; + } + if (insignal_len == SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)) { + input_fft = input_signal; + mexPrintf("Input is after fft\n"); + } else { + input_fft = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + srslte_ofdm_rx_sf(&ofdm_tx, input_signal, input_fft); + mexPrintf("Input is before fft\n"); + free(input_signal); + } + + if (nrhs > NOF_INPUTS) { + cf_t *cearray = NULL; + mexutils_read_cf(prhs[NOF_INPUTS], &cearray); + cf_t *cearray_ptr = cearray; + for (int j=0;j NOF_INPUTS + 1) { + noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); + } else if (nrhs > NOF_INPUTS) { + noise_power = 0; + } else { + noise_power = srslte_chest_ul_get_noise_estimate(&chest); + } + + r = srslte_pusch_uci_decode(&pusch, &cfg, &softbuffer, input_fft, ce, noise_power, data_bytes, &uci_data); + } + + uint8_t *data = malloc(grant.mcs.tbs); + srslte_bit_unpack_vector(data_bytes, data, grant.mcs.tbs); + + if (nlhs >= 1) { + plhs[0] = mxCreateLogicalScalar(r == 0); + } + if (nlhs >= 2) { + mexutils_write_uint8(uci_data.uci_cqi, &plhs[1], uci_data.uci_cqi_len, 1); + } + if (nlhs >= 3 && uci_data.uci_ri_len <= 1) { + mexutils_write_uint8(&uci_data.uci_ri, &plhs[2], uci_data.uci_ri_len, 1); + } + if (nlhs >= 4 && uci_data.uci_ack_len <= 1) { + mexutils_write_uint8(&uci_data.uci_ack, &plhs[3], uci_data.uci_ack_len, 1); + } + + srslte_softbuffer_rx_free(&softbuffer); + srslte_chest_ul_free(&chest); + srslte_pusch_free(&pusch); + srslte_ofdm_rx_free(&ofdm_tx); + + free(ce); + free(data_bytes); + free(data); + if (input_fft) { + free(input_fft); + } + + return; +} +