diff --git a/matlab/tests/diversity_decode_test.m b/matlab/tests/diversity_decode_test.m index 9f21a971b..536feebdc 100644 --- a/matlab/tests/diversity_decode_test.m +++ b/matlab/tests/diversity_decode_test.m @@ -10,7 +10,7 @@ cec.InterpWinSize = 1; cec.InterpWindow = 'Causal'; cfg.Seed = 1; % Random channel seed -cfg.NRxAnts = 1; % 1 receive antenna +cfg.NRxAnts = 2; % 1 receive antenna cfg.DelayProfile = 'ETU'; % EVA delay spread cfg.DopplerFreq = 100; % 120Hz Doppler frequency cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation @@ -29,16 +29,20 @@ txWaveform = txWaveform+complex(randn(n,2),randn(n,2))*1e-3; rxWaveform = lteFadingChannel(cfg,txWaveform); -rxGrid = lteOFDMDemodulate(enb,sum(rxWaveform,2)); +rxGrid = lteOFDMDemodulate(enb,rxWaveform); [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); +s=size(h); +p=s(1); +Nt=s(4); +Nr=s(3); -output_mat = lteTransmitDiversityDecode(signal(, hest(1:598,1,:)); -output_srs = srslte_diversitydecode(signal(1:598), hest(1:598,1,:)); +rx=reshape(rxGrid(:,1,:),p,Nr); +hp=reshape(h(:,1,:,:),p,Nr,Nt); + +output_mat = lteTransmitDiversityDecode(rx, hp); +output_srs = srslte_diversitydecode(rx, hp); plot(abs(output_mat-output_srs)) mean(abs(output_mat-output_srs).^2) diff --git a/matlab/tests/pdsch_equal.m b/matlab/tests/pdsch_equal.m index 665ff8047..d418f485a 100644 --- a/matlab/tests/pdsch_equal.m +++ b/matlab/tests/pdsch_equal.m @@ -10,30 +10,6 @@ recordedSignal=[]; Npackets = 1; SNR_values = 56;%linspace(2,6,10); -Lp=12; -N=256; -K=180; -rstart=(N-K)/2; -P=K/6; -Rhphp=zeros(P,P); -Rhhp=zeros(K,P); -Rhh=zeros(K,K); - -t=0:Lp-1; -alfa=log(2*Lp)/Lp; -c_l=exp(-t*alfa); -c_l=c_l/sum(c_l); -C_l=diag(1./c_l); -prows=rstart+(1:6:K); - -F=dftmtx(N); -F_p=F(prows,1:Lp); -F_l=F((rstart+1):(K+rstart),1:Lp); -Wi=(F_p'*F_p+C_l*0.01)^(-1); -W2=F_l*Wi*F_p'; -w2=reshape(transpose(W2),1,[]); - - %% Choose RMC [waveform,rgrid,rmccFgOut] = lteRMCDLTool('R.5',[1;0;0;1]); waveform = sum(waveform,2); @@ -53,11 +29,11 @@ end flen=rmccFgOut.SamplingRate/1000; -Nsf = 2; +Nsf = 1; %% Setup Fading channel model cfg.Seed = 0; % Random channel seed -cfg.NRxAnts = 1; % 1 receive antenna +cfg.NRxAnts = 2; % 1 receive antenna cfg.DelayProfile = 'EPA'; % EVA delay spread cfg.DopplerFreq = 5; % 120Hz Doppler frequency cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation @@ -87,16 +63,13 @@ for snr_idx=1:length(SNR_values) SNR = 10^(SNRdB/10); % Linear SNR N0 = 1/(sqrt(2.0*rmccFgOut.CellRefP*double(rmccFgOut.Nfft))*SNR); - Rhphp=zeros(30,30); - Rhhp=zeros(180,30); - for i=1:Npackets if isempty(recordedSignal) %% Fading [rxWaveform, chinfo] = lteFadingChannel(cfg,waveform); - rxWaveform = rxWaveform(chinfo.ChannelFilterDelay+1:end); + rxWaveform = rxWaveform(chinfo.ChannelFilterDelay+1:end,:); %rxWaveform = waveform; %% Noise Addition @@ -111,12 +84,12 @@ for snr_idx=1:length(SNR_values) for sf_idx=0:Nsf-1 % sf_idx=9; - subframe_rx=frame_rx(:,sf_idx*14+1:(sf_idx+1)*14); + subframe_rx=frame_rx(:,sf_idx*14+1:(sf_idx+1)*14,:); rmccFgOut.NSubframe=sf_idx; rmccFgOut.TotSubframes=1; % Perform channel estimation - [hest, nest,estimates] = lteDLChannelEstimate2(rmccFgOut, cec, subframe_rx); + [hest, nest] = lteDLChannelEstimate(rmccFgOut, cec, subframe_rx); [cws,symbols] = ltePDSCHDecode(rmccFgOut,rmccFgOut.PDSCH,subframe_rx,hest,nest); [trblkout,blkcrc,dstate] = lteDLSCHDecode(rmccFgOut,rmccFgOut.PDSCH, ... @@ -155,7 +128,8 @@ if (length(SNR_values)>1) ylabel('BLER') axis([min(SNR_values) max(SNR_values) 1/Npackets/(Nsf+1) 1]) else - scatter(real(symbols{1}),imag(symbols{1})) + plot(abs(symbols{1}-pdschSymbols2)) + %scatter(real(symbols{1}),imag(symbols{1})) fprintf('Matlab: %d OK\nsrsLTE: %d OK\n',decoded, decoded_srslte); end diff --git a/srslte/include/srslte/common/phy_common.h b/srslte/include/srslte/common/phy_common.h index 81cce7b66..ec308ae8b 100644 --- a/srslte/include/srslte/common/phy_common.h +++ b/srslte/include/srslte/common/phy_common.h @@ -49,6 +49,7 @@ #define SRSLTE_PC_MAX 23 // Maximum TX power for Category 1 UE (in dBm) +#define SRSLTE_MAX_RXANT 2 #define SRSLTE_MAX_PORTS 4 #define SRSLTE_MAX_LAYERS 8 #define SRSLTE_MAX_CODEWORDS 2 diff --git a/srslte/include/srslte/mimo/precoding.h b/srslte/include/srslte/mimo/precoding.h index 3e95494b5..667e1d02b 100644 --- a/srslte/include/srslte/mimo/precoding.h +++ b/srslte/include/srslte/mimo/precoding.h @@ -70,6 +70,13 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y, int nof_symbols, float noise_estimate); +SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_RXANT], + cf_t *h[SRSLTE_MAX_RXANT], + cf_t *x, + int nof_rxant, + int nof_symbols, + float noise_estimate); + SRSLTE_API int srslte_predecoding_diversity(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], diff --git a/srslte/lib/mimo/precoding.c b/srslte/lib/mimo/precoding.c index 6a6dab7ff..3b1d9a649 100644 --- a/srslte/lib/mimo/precoding.c +++ b/srslte/lib/mimo/precoding.c @@ -37,13 +37,13 @@ #ifdef LV_HAVE_SSE #include #include -int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate); +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_RXANT], cf_t *h[SRSLTE_MAX_RXANT], cf_t *x, int nof_rxant, 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 #ifdef LV_HAVE_AVX #include -int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate); +int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_RXANT], cf_t *h[SRSLTE_MAX_RXANT], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); #endif @@ -58,40 +58,75 @@ int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl #define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b))) -int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) { +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_RXANT], cf_t *h[SRSLTE_MAX_RXANT], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { float *xPtr = (float*) x; - const float *hPtr = (const float*) h; - const float *yPtr = (const float*) y; + const float *hPtr1 = (const float*) h[0]; + const float *yPtr1 = (const float*) y[0]; + const float *hPtr2 = (const float*) h[1]; + const float *yPtr2 = (const float*) y[1]; __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); __m128 noise = _mm_set1_ps(noise_estimate); - __m128 h1Val, h2Val, y1Val, y2Val, h12square, h1square, h2square, h1conj, h2conj, x1Val, x2Val; + __m128 h1Val1, h2Val1, y1Val1, y2Val1; + __m128 h1Val2, h2Val2, y1Val2, y2Val2; + __m128 h12square1, h1square1, h2square1, h1conj1, h2conj1, x1Val1, x2Val1; + __m128 h12square2, h1square2, h2square2, h1conj2, h2conj2, x1Val2, x2Val2; + for (int i=0;i 0) { - h12square = _mm_add_ps(h12square, noise); + h12square1 = _mm_add_ps(h12square1, noise); } - h1square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(1, 1, 0, 0)); - h2square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(3, 3, 2, 2)); + h1square1 = _mm_shuffle_ps(h12square1, h12square1, _MM_SHUFFLE(1, 1, 0, 0)); + h2square1 = _mm_shuffle_ps(h12square1, h12square1, _MM_SHUFFLE(3, 3, 2, 2)); + + if (nof_rxant == 2) { + h1square2 = _mm_shuffle_ps(h12square2, h12square2, _MM_SHUFFLE(1, 1, 0, 0)); + h2square2 = _mm_shuffle_ps(h12square2, h12square2, _MM_SHUFFLE(3, 3, 2, 2)); + + h1square1 = _mm_add_ps(h1square1, h1square2); + h2square1 = _mm_add_ps(h2square1, h2square2); + } /* Conjugate channel */ - h1conj = _mm_xor_ps(h1Val, conjugator); - h2conj = _mm_xor_ps(h2Val, conjugator); + h1conj1 = _mm_xor_ps(h1Val1, conjugator); + h2conj1 = _mm_xor_ps(h2Val1, conjugator); + if (nof_rxant == 2) { + h1conj2 = _mm_xor_ps(h1Val2, conjugator); + h2conj2 = _mm_xor_ps(h2Val2, conjugator); + } + /* Complex product */ - x1Val = PROD(y1Val, h1conj); - x2Val = PROD(y2Val, h2conj); + x1Val1 = PROD(y1Val1, h1conj1); + x2Val1 = PROD(y2Val1, h2conj1); - x1Val = _mm_div_ps(x1Val, h1square); - x2Val = _mm_div_ps(x2Val, h2square); + if (nof_rxant == 2) { + x1Val2 = PROD(y1Val2, h1conj2); + x2Val2 = PROD(y2Val2, h2conj2); + } + + x1Val1 = _mm_div_ps(x1Val1, h1square1); + x2Val1 = _mm_div_ps(x2Val1, h2square1); _mm_store_ps(xPtr, x1Val); xPtr+=4; _mm_store_ps(xPtr, x2Val); xPtr+=4; @@ -110,7 +145,7 @@ int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl -int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) { +int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_RXANT], cf_t *h[SRSLTE_MAX_RXANT], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { float *xPtr = (float*) x; const float *hPtr = (const float*) h; @@ -160,15 +195,28 @@ int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl #endif -int srslte_predecoding_single_gen(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) { +int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_RXANT], cf_t *h[SRSLTE_MAX_RXANT], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { for (int i=0;i 32) { return srslte_predecoding_single_avx(y, h, x, nof_symbols, noise_estimate); @@ -183,7 +231,28 @@ int srslte_predecoding_single(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); } #else + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + #endif +#endif +} + +/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ +int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_RXANT], cf_t *h[SRSLTE_MAX_RXANT], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { +#ifdef LV_HAVE_AVX + if (nof_symbols > 32) { + return srslte_predecoding_single_avx(y, h, x, nof_symbols, noise_estimate); + } else { return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); + } +#else + #ifdef LV_HAVE_SSE + if (nof_symbols > 32) { + return srslte_predecoding_single_sse(y, h, x, nof_symbols, noise_estimate); + } else { + return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); + } + #else + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); #endif #endif }