diff --git a/matlab/tests/pucch_bler.m b/matlab/tests/pucch_bler.m new file mode 100644 index 000000000..4bac59411 --- /dev/null +++ b/matlab/tests/pucch_bler.m @@ -0,0 +1,133 @@ +clear +ueConfig=struct('NCellID',1,'RNTI',11,'NULRB',25,'NSubframe',0,'CyclicPrefixUL','Normal','NTxAnts',1,'Hopping','Off'); +pucchConfig=struct('NLayers',1,'OrthCover','Off','Shortened',0,'ResourceSize',2); + +format_str={'1','1a'}; + +threshold=[0.5 0]; +formats=[1]; +pucchConfig.ResourceIdx= 0; +pucchConfig.DeltaShift = 1; +pucchConfig.CyclicShifts = 0; +ueConfig.NSubframe=0; + +enable_fading=false; + +SNR_values=-5;%linspace(-8,0,8); +Nreal=50; + +% Setup Fading channel model +cfg.Seed = 8; % Random channel seed +cfg.NRxAnts = 1; % 1 receive antenna +cfg.DelayProfile = 'EVA'; % EVA delay spread +cfg.DopplerFreq = 5; % 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 + +% Setup matlab channel equalizer +cec.PilotAverage = 'UserDefined'; % Type of pilot averaging +cec.FreqWindow = 9; % Frequency window size +cec.TimeWindow = 9; % Time window size +cec.InterpType = 'linear'; % 2D interpolation type +cec.InterpWindow = 'Causal'; % Interpolation window type +cec.InterpWinSize = 1; % Interpolation window size + + +addpath('../../debug/srslte/lib/phch/test') + + +ber=zeros(length(formats),length(SNR_values)); +ber2=zeros(length(formats),length(SNR_values)); +for f=1:length(formats) + nb=formats(f); + for s=1:length(SNR_values) + SNRdB=SNR_values(s); + SNR = 10^(SNRdB/10); % Linear SNR + + errors = 0; + errors2 = 0; + for n=1:Nreal + bits=randi(2,nb-1,1)-1; + + [sym_mat, info]=ltePUCCH1(ueConfig,pucchConfig,bits); + idx=ltePUCCH1Indices(ueConfig,pucchConfig); + [dmrs_mat, info_dmrs]=ltePUCCH1DRS(ueConfig,pucchConfig); + idx_dmrs=ltePUCCH1DRSIndices(ueConfig,pucchConfig); + + % Resource mapping + subframe_tx = lteULResourceGrid(ueConfig); + subframe_tx(idx)=sym_mat; + subframe_tx(idx_dmrs)=dmrs_mat; + + [txWaveform, info] = lteSCFDMAModulate(ueConfig,subframe_tx); + cfg.SamplingRate = info.SamplingRate; + + % Fading + if (enable_fading) + rxWaveform = lteFadingChannel(cfg,txWaveform); + else + rxWaveform = txWaveform; + end + + % Noise Addition + N0 = 1/(sqrt(2.0*double(info.Nfft))*SNR); + noise = N0*complex(randn(size(rxWaveform)), randn(size(rxWaveform))); % Generate noise + rxWaveform = rxWaveform + noise; + + % Demodulate + subframe_rx = lteSCFDMADemodulate(ueConfig, rxWaveform); + + % Perform channel estimation + [hest, nest] = lteULChannelEstimatePUCCH1(ueConfig, pucchConfig, cec, subframe_rx); + + % Equalize + pucchSymbols = lteEqualizeMMSE(subframe_rx(idx), hest(idx), nest); + + % Decoding + bits_rx = ltePUCCH1Decode(ueConfig, pucchConfig, length(bits), pucchSymbols); + + % Check errors + a=size(bits_rx); + if (a(2) ~= 1) + errors = errors + 1; + elseif (formats(f) == 2) + if (a(1) ~= 1) + errors = errors + 1; + elseif (bits_rx(1) ~= bits(1)) + errors = errors + 1; + end + end + + % Decoding srsLTE + [bits_rx,z,ce]= srslte_pucch(ueConfig, pucchConfig, length(bits), subframe_rx, threshold); + + % Check errors + a=size(bits_rx); + if (a(2) ~= 1) + errors2 = errors2 + 1; + elseif (formats(f) == 2) + if (a(1) ~= 1) + errors2 = errors2 + 1; + elseif (bits_rx(1) ~= bits(1)) + errors2 = errors2 + 1; + end + end + + end + ber(f,s)=errors/Nreal; + ber2(f,s)=errors2/Nreal; + fprintf('Format %s, SNR=%.1f dB, errors=%d, errors2=%d\n', format_str{formats(f)},SNRdB,errors,errors2); + end +end + +semilogy(SNR_values,ber,SNR_values,ber2) +xlabel('SNR (dB)') +ylabel('BER') +grid on +legend(format_str(formats)) + diff --git a/srslte/lib/enb/enb_ul.c b/srslte/lib/enb/enb_ul.c index a5b16ea3f..a558b28e7 100644 --- a/srslte/lib/enb/enb_ul.c +++ b/srslte/lib/enb/enb_ul.c @@ -238,7 +238,7 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, srslte_pucch_format_t format, ui } break; default: - fprintf(stderr, "Error getting PUCCH format %d not supported\n"); + fprintf(stderr, "Error getting PUCCH format %d not supported\n", format); return SRSLTE_ERROR; } diff --git a/srslte/lib/phch/test/pucch_test_mex.c b/srslte/lib/phch/test/pucch_test_mex.c new file mode 100644 index 000000000..c65097b11 --- /dev/null +++ b/srslte/lib/phch/test/pucch_test_mex.c @@ -0,0 +1,225 @@ +/** + * + * \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 PUCCHCFG prhs[1] +#define N_BITS prhs[2] +#define INPUT prhs[3] +#define THRESHOLD prhs[4] +#define NOF_INPUTS 4 + +void help() +{ + mexErrMsgTxt + ("[data, symbols, ce]=srslte_pucch(ue, chs, n_bits, input)\n\n"); +} + +/* the gateway function */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + + if (nrhs < NOF_INPUTS) { + help(); + return; + } + srslte_verbose = SRSLTE_VERBOSE_NONE; + + srslte_cell_t cell; + bzero(&cell, sizeof(srslte_cell_t)); + cell.nof_ports = 1; + cell.cp = SRSLTE_CP_NORM; + 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_pucch_t pucch; + if (srslte_pucch_init(&pucch, cell)) { + mexErrMsgTxt("Error initiating PUSCH\n"); + return; + } + + uint32_t sf_idx = 0; + if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) { + mexErrMsgTxt("Field NSubframe not found in UE config\n"); + return; + } + uint32_t rnti; + if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti)) { + mexErrMsgTxt("Field NSubframe not found in UE config\n"); + return; + } + if (srslte_pucch_set_crnti(&pucch, (uint16_t) rnti&0xffff)) { + mexErrMsgTxt("Error setting C-RNTI\n"); + return; + } + uint32_t n_pucch; + if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceIdx", &n_pucch)) { + mexErrMsgTxt("Field ResourceIdx not found in PUCCHCFG\n"); + return; + } + srslte_pucch_cfg_t pucch_cfg; + bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); + + if (mexutils_read_uint32_struct(PUCCHCFG, "DeltaShift", &pucch_cfg.delta_pucch_shift)) { + mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n"); + return; + } + if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceSize", &pucch_cfg.n_rb_2)) { + mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n"); + return; + } + if (mexutils_read_uint32_struct(PUCCHCFG, "CyclicShifts", &pucch_cfg.N_cs)) { + mexErrMsgTxt("Field CyclicShifts not found in PUCCHCFG\n"); + return; + } + bool group_hopping_en = false; + char *hop = mexutils_get_char_struct(UECFG, "Hopping"); + if (hop) { + if (!strcmp(hop, "Group")) { + group_hopping_en = true; + } + mxFree(hop); + } + + pucch.shortened = false; + uint32_t sh = 0; + mexutils_read_uint32_struct(PUCCHCFG, "Shortened", &sh); + if (sh == 1) { + pucch.shortened = true; + } + + float *thresholds; + int th_len = 0; + + if (nrhs > NOF_INPUTS) { + th_len = mexutils_read_f(THRESHOLD, &thresholds); + if (th_len == 2) { + srslte_pucch_set_threshold(&pucch, thresholds[0], thresholds[1]); + } + } + + uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; + int nof_bits = (int) mxGetScalar(N_BITS); + + srslte_pucch_format_t format; + switch(nof_bits) { + case 0: + format = SRSLTE_PUCCH_FORMAT_1; + break; + case 1: + format = SRSLTE_PUCCH_FORMAT_1A; + break; + case 2: + format = SRSLTE_PUCCH_FORMAT_1B; + break; + case 20: + format = SRSLTE_PUCCH_FORMAT_2; + break; + case 21: + format = SRSLTE_PUCCH_FORMAT_2A; + break; + case 22: + format = SRSLTE_PUCCH_FORMAT_2B; + break; + default: + mexErrMsgTxt("Invalid number of bits in parameter ack\n"); + return; + } + if (nof_bits > 20) { + nof_bits = 20; + } + + cf_t *sf_symbols = NULL; + int nof_re = mexutils_read_cf(INPUT, &sf_symbols); + if (nof_re < 0) { + mexErrMsgTxt("Error reading input\n"); + return; + } + cf_t *ce = srslte_vec_malloc(nof_re*sizeof(cf_t)); + if (!ce) { + perror("malloc"); + return; + } + bzero(ce, nof_re*sizeof(cf_t)); + srslte_chest_ul_t chest_ul; + if (srslte_chest_ul_init(&chest_ul, cell)) { + mexErrMsgTxt("Error initiating PUCCH DMRS\n"); + return; + } + srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; + pusch_cfg.group_hopping_en = group_hopping_en; + pusch_cfg.sequence_hopping_en = false; + srslte_chest_ul_set_cfg(&chest_ul, &pusch_cfg, &pucch_cfg, NULL); + + srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en); + + if (srslte_chest_ul_estimate_pucch(&chest_ul, sf_symbols, ce, format, n_pucch, sf_idx)) { + mexErrMsgTxt("Error estimating PUCCH DMRS\n"); + return; + } + + if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, sf_symbols, ce, 0, bits)) { + mexErrMsgTxt("Error decoding PUCCH\n"); + return; + } + + if (nlhs >= 1) { + if (format != SRSLTE_PUCCH_FORMAT_1) { + mexutils_write_uint8(bits, &plhs[0], nof_bits, 1); + } else { + if (bits[0] == 1) { + mexutils_write_uint8(bits, &plhs[0], 0, 1); + } else { + mexutils_write_uint8(bits, &plhs[0], 0, 0); + } + } + } + + if (nlhs >= 2) { + mexutils_write_cf(pucch.z, &plhs[1], 2*srslte_refsignal_dmrs_N_rs(format, cell.cp)*SRSLTE_NRE*2, 1); + } + + if (nlhs >= 3) { + mexutils_write_cf(ce, &plhs[2], nof_re, 1); + } + + srslte_pucch_free(&pucch); + free(sf_symbols); + + return; +} + diff --git a/srslte/lib/rf/rf_uhd_imp.c b/srslte/lib/rf/rf_uhd_imp.c index 5ada6165a..d9683424d 100644 --- a/srslte/lib/rf/rf_uhd_imp.c +++ b/srslte/lib/rf/rf_uhd_imp.c @@ -315,7 +315,7 @@ int rf_uhd_open(char *args, void **h) // Set external clock reference if (strstr(args, "clock=external")) { - uhd_usrp_set_clock_source(handler->usrp, "external", 0); + uhd_usrp_set_clock_source(handler->usrp, "external", 0); } handler->has_rssi = get_has_rssi(handler);