diff --git a/matlab/common/write_c_struct_complex.m b/matlab/common/write_c_struct_complex.m new file mode 100644 index 000000000..41f312b90 --- /dev/null +++ b/matlab/common/write_c_struct_complex.m @@ -0,0 +1,16 @@ +function [ out ] = write_c_struct_complex( filename, varname, x) + + [tidin msg]=fopen(filename,'wt'); + if (tidin==-1) + fprintf('error opening %s: %s\n',filename, msg); + out=[]; + return + end + fprintf(tidin, 'float %s[%d]={%.9g,%.9g',varname,2*length(x),real(x(1)),imag(x(1))); + for i=2:length(x) + fprintf(tidin, ',\n %.9g,%.9g',real(x(i)),imag(x(i))); + end + fprintf(tidin, '};\n'); + fclose(tidin); +end + diff --git a/matlab/tests/dlsch_test.m b/matlab/tests/dlsch_test.m index 15769f191..120c1d4c9 100644 --- a/matlab/tests/dlsch_test.m +++ b/matlab/tests/dlsch_test.m @@ -1,25 +1,47 @@ clear -enbConfig=struct('NCellID',1,'CyclicPrefix','Normal','CellRefP',1); -pdschConfig=struct('Modulation','64QAM','RV',0,'TxScheme','Port0'); +enbConfig=struct('NCellID',0,'CyclicPrefix','Normal','CellRefP',1); +pdschConfig=struct('Modulation','64QAM','RV',1,'TxScheme','Port0','NTurboDecIts',10); addpath('../../build/srslte/lib/phch/test') -TBs=36696; -e_bits=41400; -error=zeros(size(TBs)); -for i=1:length(TBs) - trblkin=randi(2,TBs(i),1)-1; +%TBs=18336; +i=1; +e_bits=3450*6; +%error=zeros(size(TBs)); +%for i=1:length(TBs) + %trblkin=randi(2,TBs(i),1)-1; + trblkin=read_uchar('../../build/data_in'); + fprintf('e_bits=%d, trblkin=%d\n',e_bits,length(trblkin)); + [mat, info]=lteDLSCH(enbConfig,pdschConfig,e_bits,trblkin); lib=srslte_dlsch_encode(enbConfig,pdschConfig,e_bits,trblkin); error(i)=mean(abs(double(mat)-double(lib))); -end - -if (length(TBs) == 1) - %disp(info) - disp(error) - n=1:length(mat); - plot(abs(double(mat)-double(lib))) -else - plot(error) -end + mat(mat==0)=-1; + mat=mat*10; + + rec = lteRateRecoverTurbo(mat,length(trblkin),pdschConfig.RV); + rec2 = reshape(reshape(rec{1},[],3)',[],1); + out = lteTurboDecode(rec{1}); + + x=read_int16('../../build/rmout_0.dat'); + subplot(2,1,1) + plot(abs(double(x)-double(rec2))); + t=1:100; + %plot(t,double(x(t)),t,double(rec2(t))) + subplot(2,1,2) + llr=read_int16('../../build/llr.dat'); + plot(abs(double(mat)-double(llr))) + + [data, crc,state] = lteDLSCHDecode(enbConfig, pdschConfig, length(trblkin), mat); + disp(crc) +%end +% +% if (length(TBs) == 1) +% %disp(info) +% disp(error) +% n=1:length(mat); +% plot(abs(double(mat)-double(lib))) +% else +% plot(error) +% end diff --git a/matlab/tests/equalizer_test.m b/matlab/tests/equalizer_test.m index ecc3c4cc2..45bde11a8 100644 --- a/matlab/tests/equalizer_test.m +++ b/matlab/tests/equalizer_test.m @@ -6,30 +6,35 @@ clear plot_noise_estimation_only=false; -SNR_values_db=10;%linspace(0,30,8); -Nrealizations=1 ; +SNR_values_db=30;%linspace(0,30,8); +Nrealizations=1; -preEVM = zeros(length(SNR_values_db),Nrealizations); -postEVM_mmse = zeros(length(SNR_values_db),Nrealizations); -postEVM_mmse_lin = zeros(length(SNR_values_db),Nrealizations); -postEVM_srslte = zeros(length(SNR_values_db),Nrealizations); +Lp=5; +N=512; +enb.NDLRB = 25; % Number of resource blocks - -enb.NDLRB = 6; % Number of resource blocks enb.CellRefP = 1; % One transmit antenna port -enb.NCellID = 0; % Cell ID +enb.NCellID = 0; % Cell ID enb.CyclicPrefix = 'Normal'; % Normal cyclic prefix enb.DuplexMode = 'FDD'; % FDD -%% Channel Model Configuration -rng(1); % Configure random number generators +K=enb.NDLRB*12; +rstart=(N-K)/2; +P=K/6; +Rhphp=zeros(P,P); +Rhhp=zeros(K,P); +Rhh=zeros(K,K); -cfg.Seed = 2; % Random channel seed -cfg.NRxAnts = 2; % 1 receive antenna -cfg.DelayProfile = 'EVA'; % EVA delay spread -cfg.DopplerFreq = 120; % 120Hz Doppler frequency +%% Channel Model Configuration +cfg.Seed = 0; % Random channel seed +cfg.InitTime = 0; +cfg.NRxAnts = 1; % 1 receive antenna +cfg.DelayProfile = 'EPA'; + +% doppler 5, 70 300 + +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 @@ -42,25 +47,42 @@ cec.PilotAverage = 'UserDefined'; % Type of pilot symbol averaging cec.FreqWindow = 9; % Frequency window size cec.TimeWindow = 9; % Time window size cec.InterpType = 'Linear'; % 2D interpolation type -cec.InterpWindow = 'Centered'; % Interpolation window type +cec.InterpWindow = 'Causal'; % Interpolation window type cec.InterpWinSize = 1; % Interpolation window size %% Subframe Resource Grid Size gridsize = lteDLResourceGridSize(enb); -K = gridsize(1); % Number of subcarriers +Ks = gridsize(1); % Number of subcarriers L = gridsize(2); % Number of OFDM symbols in one subframe -P = gridsize(3); % Number of transmit antenna ports +Ports = gridsize(3); % Number of transmit antenna ports + +%% Allocate memory +Ntests=4; +hest=cell(1,Ntests); +for i=1:Ntests + hest{i}=zeros(K,140); +end +hls=zeros(4,4*P*10); +MSE=zeros(Ntests,Nrealizations,length(SNR_values_db)); +noiseEst=zeros(Ntests,Nrealizations,length(SNR_values_db)); + +legends={'matlab','ls.linear','mmse','r.smooth'}; +colors={'bo-','rx-','m*-','k+-','c+-'}; +colors2={'b-','r-','m-','k-','c-'}; + +addpath('../../build/srslte/lib/ch_estimation/test') + +offset=-1; for nreal=1:Nrealizations %% Transmit Resource Grid txGrid = []; -RSRP = []; %% Payload Data Generation % Number of bits needed is size of resource grid (K*L*P) * number of bits % per symbol (2 for QPSK) -numberOfBits = K*L*P*2; +numberOfBits = Ks*L*Ports*2; % Create random bit stream inputBits = randi([0 1], numberOfBits, 1); @@ -104,7 +126,7 @@ for sf = 0:10 end -txGrid([1:5 68:72],6:7) = zeros(10,2); +txGrid([1:5 68:72],6:7) = ones(10,2); %% OFDM Modulation @@ -112,19 +134,16 @@ txGrid([1:5 68:72],6:7) = zeros(10,2); txGrid = txGrid(:,1:140); %% SNR Configuration - for snr_idx=1:length(SNR_values_db) SNRdB = SNR_values_db(snr_idx); % Desired SNR in dB SNR = 10^(SNRdB/20); % Linear SNR +fprintf('SNR=%.1f dB\n',SNRdB) %% Fading Channel cfg.SamplingRate = info.SamplingRate; - -% Pass data through the fading channel model -%rxWaveform = lteFadingChannel(cfg,txWaveform); -rxWaveform = txWaveform; +[rxWaveform, chinfo] = lteFadingChannel(cfg,txWaveform); %% Additive Noise @@ -134,91 +153,176 @@ N0 = 1/(sqrt(2.0*enb.CellRefP*double(info.Nfft))*SNR); % Create additive white Gaussian noise noise = N0*complex(randn(size(rxWaveform)),randn(size(rxWaveform))); -noiseTx(snr_idx) = N0; % Add noise to the received time domain waveform +rxWaveform_nonoise = rxWaveform; rxWaveform = rxWaveform + noise; %% Synchronization -offset = lteDLFrameOffset(enb,rxWaveform); -rxWaveform = rxWaveform(1+offset+2:end,:); +if (offset==-1) + offset = lteDLFrameOffset(enb,rxWaveform); +end + +rxWaveform = rxWaveform(1+offset:end,:); +rxWaveform_nonoise = rxWaveform_nonoise(1+offset:end,:); %% OFDM Demodulation rxGrid = lteOFDMDemodulate(enb,rxWaveform); rxGrid = rxGrid(:,1:140); -addpath('../../build/srslte/lib/ch_estimation/test') +rxGrid_nonoise = lteOFDMDemodulate(enb,rxWaveform_nonoise); +rxGrid_nonoise = rxGrid_nonoise(:,1:140); -%% Channel Estimation -[estChannel, noiseEst(snr_idx)] = lteDLChannelEstimate(enb,cec,rxGrid); -output=[]; -snrest_srslte = zeros(10,1); -noise_srslte = zeros(10,1); -rsrp = zeros(1,10); +% True channel +h=rxGrid_nonoise./(txGrid); -[d, ~, out] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid); -output = [output out]; -%RSRP = [RSRP rsrp]; -%meanRSRP(snr_idx)=mean(rsrp); -%SNR_srslte(snr_idx)=mean(snrest_srslte); -%noiseEst_srslte(snr_idx)=mean(noise_srslte); -d=reshape(d, size(estChannel)); -plot(1:288,real(reshape(estChannel(:,11:14),1,[])),'b-',... - 1:288,real(reshape(d(:,11:14),1,[])),'r-') -% if ~plot_noise_estimation_only -% -% %% MMSE Equalization -% eqGrid_mmse = lteEqualizeMMSE(rxGrid, estChannel, noiseEst(snr_idx)); -% -% eqGrid_srslte = reshape(output,size(eqGrid_mmse)); -% -% % Analysis -% -% %Compute EVM across all input values EVM of pre-equalized receive signal -% preEqualisedEVM = lteEVM(txGrid,rxGrid); -% fprintf('%d-%d: Pre-EQ: %0.3f%%\n', ... -% snr_idx,nreal,preEqualisedEVM.RMS*100); -% -% -% %EVM of post-equalized receive signal -% postEqualisedEVM_mmse = lteEVM(txGrid,reshape(eqGrid_mmse,size(txGrid))); -% fprintf('%d-%d: MMSE: %0.3f%%\n', ... -% snr_idx,nreal,postEqualisedEVM_mmse.RMS*100); -% -% postEqualisedEVM_srslte = lteEVM(txGrid,reshape(eqGrid_srslte,size(txGrid))); -% fprintf('%d-%d: srslte: %0.3f%%\n', ... -% snr_idx,nreal,postEqualisedEVM_srslte.RMS*100); -% -% preEVM(snr_idx,nreal) = preEqualisedEVM.RMS; -% postEVM_mmse(snr_idx,nreal) = mean([postEqualisedEVM_mmse.RMS]); -% postEVM_srslte(snr_idx,nreal) = mean([postEqualisedEVM_srslte.RMS]); -% end +%% Channel Estimation with Matlab +tmpnoise=zeros(10,1); +for i=1:10 + enb.NSubframe=i-1; + [hest{1}(:,(1:14)+(i-1)*14), tmpnoise(i), hls(:,(1:4*P)+(i-1)*4*P)] = ... + lteDLChannelEstimate2(enb,cec,rxGrid(:,(i-1)*14+1:i*14)); +end +noiseEst(1,nreal,snr_idx)=mean(tmpnoise)*sqrt(2)*enb.CellRefP; + +%% LS-Linear estimation with srsLTE +[tmp, ~, ~, noiseEst(2,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid); +hest{2}=reshape(tmp, size(hest{1})); + +tmp_noise=zeros(2,1); +for sf=[0 5] + enb.NSubframe=sf; + pssSym = ltePSS(enb); + pssInd = ltePSSIndices(enb); + x=reshape(rxGrid(pssInd),[],1); + hh=reshape(hest{2}(pssInd),[],1); + y=hh.*pssSym; + tmp_noise(sf/5+1)=mean(abs(x-y).^2); +end +% noiseEst(2,nreal,snr_idx)=mean(tmp_noise); + +%% MMSE estimation with srsLTE + +% Compute Correlation matrices +M=40; +a=0.1; +hidx=zeros(M,1); +for i=1:M + if (mod(i,2)==1) + hx=floor((i-1)/2)*7+1; + else + hx=floor((i-1)/2)*7+5; + end + hidx(i)=hx; + hp=hest{1}(hls(1,(1:P)+P*(i-1)),hx); + Rhphp = (1-a)*Rhphp+a*(hp*hp'); + Rhhp = (1-a)*Rhhp+a*(hest{1}(:,hx)*hp'); + Rhh = (1-a)*Rhh+a*h(:,hx)*h(:,hx)'; +end +snr_lin=10^(SNR_values_db(snr_idx)/10); +Wi=((Rhphp+(1/snr_lin)*eye(P)))^-1; +W = Rhhp*Wi; + +w=reshape(transpose(W),1,[]); +[tmp, ~, ~, noiseEst(3,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid,w); +hest{3}=reshape(tmp, size(hest{1})); + + +%% Low-pass filter smoother + +prows=rstart+(1:6:K); +t=0:Lp-1; +alfa=log(2*Lp)/Lp; +c_l=exp(-t*alfa); +c_l2=[c_l zeros(1,N-Lp)]; +C_l=diag(c_l2); +F=dftmtx(N); +R_hh=F*C_l*F'; +R_hh=R_hh(prows,prows); +W3=R_hh*(R_hh+0.05*eye(P))^-1; + +w3=reshape(transpose(W3),1,[]); +[tmp, pilot_avg, ~, noiseEst(4,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid,w3); +hest{4}=reshape(tmp, size(hest{1})); + + + +%% Compute MSE +for i=1:Ntests + MSE(i,nreal,snr_idx)=mean(mean(abs(h(:,hidx)-hest{i}(:,hidx)).^2)); + fprintf('MSE test %d: %f\n',i, 10*log10(MSE(i,nreal,snr_idx))); +end + +%% Plot a single realization +if (length(SNR_values_db) == 1) + subplot(2,1,1) + sym=1; + ref_idx=1:P; + ref_idx_x=[1:6:K];% (292:6:360)-216];% 577:6:648]; + n=1:(K*length(sym)); + for i=1:Ntests + plot(n,abs(reshape(hest{i}(:,sym),1,[])),colors2{i}); + hold on; + end + plot(ref_idx_x,abs(hls(3,ref_idx)),'ro'); + hold off; + tmp=cell(Ntests+1,1); + for i=1:Ntests + tmp{i}=legends{i}; + end + tmp{Ntests+1}='LS'; + legend(tmp) + + xlabel('SNR (dB)') + ylabel('Channel Gain') + grid on; + + fprintf('Mean MMSE Robust %.2f dB\n', 10*log10(MSE(4,nreal,snr_idx))) + fprintf('Mean MMSE matlab %.2f dB\n', 10*log10(MSE(1,nreal,snr_idx))) + + subplot(2,1,2) + plot(1:P,abs(W3(P/2,:))) + +end + end end -% -% % subplot(1,2,1) -% -% if ~plot_noise_estimation_only -% plot(SNR_values_db, mean(preEVM,2), ... -% SNR_values_db, mean(postEVM_mmse,2), ... -% SNR_values_db, mean(postEVM_srslte,2)) -% legend('No Eq','MMSE-lin','MMSE-srslte') + + +%% Compute average MSE and noise estimation +mean_mse=mean(MSE,2); +mean_snr=10*log10(1./mean(noiseEst,2)); + + +%% Plot average over all SNR values +if (length(SNR_values_db) > 1) + subplot(1,1,1) + for i=1:Ntests + plot(SNR_values_db, 10*log10(mean_mse(i,:)),colors{i}) + hold on; + end + hold off; + legend(legends); + grid on + xlabel('SNR (dB)') + ylabel('MSE (dB)') + +% subplot(1,2,2) +% plot(SNR_values_db, SNR_values_db,'k:') +% hold on; +% for i=1:Ntests +% plot(SNR_values_db, mean_snr(i,:), colors{i}) +% end +% hold off +% tmp=cell(Ntests+1,1); +% tmp{1}='Theory'; +% for i=2:Ntests+1 +% tmp{i}=legends{i-1}; +% end +% legend(tmp) % grid on -% end -% -% % subplot(1,2,2) -% if plot_noise_estimation_only -% SNR_matlab = 1./(noiseEst*sqrt(2.0)*enb.CellRefP); -% -% subplot(1,3,1) -% plot(SNR_values_db, SNR_values_db, SNR_values_db, 10*log10(SNR_srslte),SNR_values_db, 10*log10(SNR_matlab)) -% legend('Theory','srsLTE','Matlab') -% -% subplot(1,3,2) -% plot(SNR_values_db, 10*log10(noiseTx), SNR_values_db, 10*log10(noiseEst_srslte),SNR_values_db, 10*log10(noiseEst)) -% legend('Theory','srsLTE','Matlab') -% -% subplot(1,3,3) -% plot(1:10*length(SNR_values_db),RSRP,10*(1:length(SNR_values_db)),meanRSRP) -% end +% xlabel('SNR (dB)') +% ylabel('Estimated SNR (dB)') +end + diff --git a/matlab/tests/pdsch_bler.m b/matlab/tests/pdsch_bler.m index 0d5f4a162..2f1af0a30 100644 --- a/matlab/tests/pdsch_bler.m +++ b/matlab/tests/pdsch_bler.m @@ -2,15 +2,39 @@ %% Cell-Wide Settings % A structure |enbConfig| is used to configure the eNodeB. -%clear +%clear12 recordedSignal=[]; -Npackets = 5; -SNR_values = linspace(18,25,5); +Npackets = 20; +SNR_values = 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.9',[1;0;0;1]); +[waveform,rgrid,rmccFgOut] = lteRMCDLTool('R.0',[1;0;0;1]); waveform = sum(waveform,2); if ~isempty(recordedSignal) @@ -28,12 +52,12 @@ end flen=rmccFgOut.SamplingRate/1000; -Nsf = 10; +Nsf = 9; %% Setup Fading channel model -cfg.Seed = 8; % Random channel seed +cfg.Seed = 0; % Random channel seed cfg.NRxAnts = 1; % 1 receive antenna -cfg.DelayProfile = 'EVA'; % EVA delay spread +cfg.DelayProfile = 'EPA'; % EVA delay spread cfg.DopplerFreq = 5; % 120Hz Doppler frequency cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation cfg.InitTime = 0; % Initialize at time zero @@ -49,7 +73,7 @@ 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 = 'Centered'; % Interpolation window type +cec.InterpWindow = 'Causal'; % Interpolation window type cec.InterpWinSize = 1; % Interpolation window size addpath('../../build/srslte/lib/phch/test') @@ -61,13 +85,17 @@ for snr_idx=1:length(SNR_values) SNRdB = SNR_values(snr_idx); 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 = lteFadingChannel(cfg,waveform); - %rxWaveform = waveform; + %rxWaveform = lteFadingChannel(cfg,waveform); + rxWaveform = waveform; %% Noise Addition noise = N0*complex(randn(size(rxWaveform)), randn(size(rxWaveform))); % Generate noise @@ -86,7 +114,7 @@ for snr_idx=1:length(SNR_values) rmccFgOut.TotSubframes=1; % Perform channel estimation - [hest, nest] = lteDLChannelEstimate(rmccFgOut, cec, subframe_rx); + [hest, nest,estimates] = lteDLChannelEstimate2(rmccFgOut, cec, subframe_rx); [cws,symbols] = ltePDSCHDecode(rmccFgOut,rmccFgOut.PDSCH,subframe_rx,hest,nest); [trblkout,blkcrc,dstate] = lteDLSCHDecode(rmccFgOut,rmccFgOut.PDSCH, ... @@ -99,7 +127,7 @@ for snr_idx=1:length(SNR_values) if (rmccFgOut.PDSCH.TrBlkSizes(sf_idx+1) > 0) [dec2, data, pdschRx, pdschSymbols2, cws2] = srslte_pdsch(rmccFgOut, rmccFgOut.PDSCH, ... rmccFgOut.PDSCH.TrBlkSizes(sf_idx+1), ... - subframe_rx, hest, nest); + subframe_rx); else dec2 = 1; end @@ -117,8 +145,8 @@ for snr_idx=1:length(SNR_values) end if (length(SNR_values)>1) - semilogy(SNR_values,1-decoded/Npackets/(Nsf+1),'bo-',... - SNR_values,1-decoded_srslte/Npackets/(Nsf+1), 'ro-') + semilogy(SNR_values,1-decoded/Npackets/(Nsf),'bo-',... + SNR_values,1-decoded_srslte/Npackets/(Nsf), 'ro-') grid on; legend('Matlab','srsLTE') xlabel('SNR (dB)') diff --git a/matlab/tests/rm_turbo_rx_test.m b/matlab/tests/rm_turbo_rx_test.m index 4180a2130..a6139f251 100644 --- a/matlab/tests/rm_turbo_rx_test.m +++ b/matlab/tests/rm_turbo_rx_test.m @@ -3,7 +3,8 @@ clear enbConfig=struct('NCellID',1,'CyclicPrefix','Normal','CellRefP',1); pdschConfig=struct('Modulation','QPSK','RV',0,'TxScheme','Port0'); -addpath('../../debug/lte/phy/lib/fec/test') +addpath('../../build/srslte/lib/fec/test') + codewordLen = 12000; trBlkLenVec = 6201; @@ -11,9 +12,7 @@ error=zeros(size(trBlkLenVec)); for i=1:length(trBlkLenVec) trBlkLen=trBlkLenVec(i); in=randi(2,trBlkLen,1)-1; - - in=[1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, ]; - + RV = 0; trblockwithcrc = lteCRCEncode(in,'24A'); codeblocks = lteCodeBlockSegment(trblockwithcrc); @@ -30,7 +29,7 @@ for i=1:length(trBlkLenVec) [outLib] = srslte_turbodecoder(lib); if (length(trBlkLenVec) == 1) - fprintf('Err mat: %d. Err lib: %d\n',sum(out(1+info.F:trBlkLen+info.F)~=in),sum(outLib(1+info.F:trBlkLen+info.F)~=in)); +% fprintf('Err mat: %d. Err lib: %d\n',sum(out(1+info.F:trBlkLen+info.F)~=in),sum(outLib(1+info.F:trBlkLen+info.F)~=in)); end error(i)=mean(abs(double(mat2)-double(lib))); end diff --git a/srslte/examples/pdsch_ue.c b/srslte/examples/pdsch_ue.c index 948e29c8b..b91c566eb 100644 --- a/srslte/examples/pdsch_ue.c +++ b/srslte/examples/pdsch_ue.c @@ -39,7 +39,6 @@ #include "srslte/srslte.h" - #ifndef DISABLE_RF #include "srslte/rf/rf.h" #include "srslte/rf/rf_utils.h" @@ -407,7 +406,7 @@ int main(int argc, char **argv) { /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti); - + /* Initialize subframe counter */ sf_cnt = 0; @@ -519,9 +518,9 @@ int main(int argc, char **argv) { nof_trials++; - rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.05); - rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05); - noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); + rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1); + rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.1); + noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.1); nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -541,11 +540,11 @@ int main(int argc, char **argv) { gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); } printf("CFO: %+6.2f KHz, " - "SNR: %4.1f dB, " - "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", + "SNR: %4.1f dB, " + "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", srslte_ue_sync_get_cfo(&ue_sync)/1000, - 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), + 10*log10(rsrp/noise), 100*(1-(float) ue_dl.nof_detected/nof_trials), (float) 100*ue_dl.pkt_errors/ue_dl.pkts_total); } diff --git a/srslte/include/srslte/ch_estimation/chest_dl.h b/srslte/include/srslte/ch_estimation/chest_dl.h index 6b9147b8d..3e6668ad5 100644 --- a/srslte/include/srslte/ch_estimation/chest_dl.h +++ b/srslte/include/srslte/ch_estimation/chest_dl.h @@ -48,26 +48,20 @@ #include "srslte/resampling/interp.h" #include "srslte/ch_estimation/refsignal_dl.h" #include "srslte/common/phy_common.h" +#include "srslte/sync/pss.h" -#define SRSLTE_CHEST_MAX_FILTER_FREQ_LEN 21 -#define SRSLTE_CHEST_MAX_FILTER_TIME_LEN 40 +#define SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN 65 typedef struct { srslte_cell_t cell; srslte_refsignal_cs_t csr_signal; - cf_t *pilot_estimates[SRSLTE_MAX_PORTS]; - cf_t *pilot_estimates_average[SRSLTE_MAX_PORTS]; - cf_t *pilot_recv_signal[SRSLTE_MAX_PORTS]; - - uint32_t filter_freq_len; - float filter_freq[SRSLTE_CHEST_MAX_FILTER_FREQ_LEN]; - uint32_t filter_time_len; - float filter_time[SRSLTE_CHEST_MAX_FILTER_TIME_LEN]; - + cf_t *pilot_estimates; + cf_t *pilot_estimates_average; + cf_t *pilot_recv_signal; cf_t *tmp_noise; - cf_t *tmp_freqavg; - cf_t *tmp_timeavg[SRSLTE_CHEST_MAX_FILTER_TIME_LEN]; - cf_t *tmp_timeavg_mult; + + uint32_t smooth_filter_len; + float smooth_filter[SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN]; srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_lin_t srslte_interp_lin; @@ -75,7 +69,11 @@ typedef struct { float rssi[SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS]; - float filter_time_ema; + + /* Use PSS for noise estimation in LS linear interpolation mode */ + cf_t pss_signal[SRSLTE_PSS_LEN]; + cf_t tmp_pss[SRSLTE_PSS_LEN]; + cf_t tmp_pss_noisy[SRSLTE_PSS_LEN]; } srslte_chest_dl_t; @@ -84,16 +82,9 @@ SRSLTE_API int srslte_chest_dl_init(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q); -SRSLTE_API int srslte_chest_dl_set_filter_freq(srslte_chest_dl_t *q, - float *filter, - uint32_t filter_len); - -SRSLTE_API int srslte_chest_dl_set_filter_time(srslte_chest_dl_t *q, - float *filter, - uint32_t filter_len); - -SRSLTE_API void srslte_chest_dl_set_filter_time_ema(srslte_chest_dl_t *q, - float ema_coefficient); +SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, + float *filter, + uint32_t filter_len); SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, diff --git a/srslte/include/srslte/resampling/interp.h b/srslte/include/srslte/resampling/interp.h index a6208ad6d..e2676d286 100644 --- a/srslte/include/srslte/resampling/interp.h +++ b/srslte/include/srslte/resampling/interp.h @@ -80,7 +80,12 @@ SRSLTE_API void srslte_interp_linear_vector(srslte_interp_linsrslte_vec_t *q, cf_t *between, uint32_t M); - +SRSLTE_API void srslte_interp_linear_vector2(srslte_interp_linsrslte_vec_t *q, + cf_t *in0, + cf_t *in1, + cf_t *start, + cf_t *between, + uint32_t M); /* Interpolation within a vector */ diff --git a/srslte/include/srslte/scrambling/scrambling.h b/srslte/include/srslte/scrambling/scrambling.h index e01861f7c..4e1fe40e6 100644 --- a/srslte/include/srslte/scrambling/scrambling.h +++ b/srslte/include/srslte/scrambling/scrambling.h @@ -49,12 +49,8 @@ SRSLTE_API void srslte_scrambling_b_offset(srslte_sequence_t *s, int len); SRSLTE_API void srslte_scrambling_bytes(srslte_sequence_t *s, - uint8_t *data); - -SRSLTE_API void srslte_scrambling_bytes_offset(srslte_sequence_t *s, - uint8_t *data, - int offset, - int len); + uint8_t *data, + int len); SRSLTE_API void srslte_scrambling_f(srslte_sequence_t *s, float *data); diff --git a/srslte/include/srslte/sync/pss.h b/srslte/include/srslte/sync/pss.h index e85df72b0..0c7830792 100644 --- a/srslte/include/srslte/sync/pss.h +++ b/srslte/include/srslte/sync/pss.h @@ -112,6 +112,11 @@ SRSLTE_API void srslte_pss_synch_reset(srslte_pss_synch_t *q); SRSLTE_API int srslte_pss_generate(cf_t *signal, uint32_t N_id_2); +SRSLTE_API void srslte_pss_get_slot(cf_t *slot, + cf_t *pss_signal, + uint32_t nof_prb, + srslte_cp_t cp); + SRSLTE_API void srslte_pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, diff --git a/srslte/lib/ch_estimation/src/chest_dl.c b/srslte/lib/ch_estimation/src/chest_dl.c index 8c4c7acf6..b660ad20b 100644 --- a/srslte/lib/ch_estimation/src/chest_dl.c +++ b/srslte/lib/ch_estimation/src/chest_dl.c @@ -39,31 +39,29 @@ #include "srslte/utils/vector.h" #include "srslte/utils/convolution.h" -#define NOISE_POWER_METHOD 1 // 0: Difference between noisy received and noiseless; 1: power of empty subcarriers +#define ESTIMATE_NOISE_LS_PSS -#define DEFAULT_FILTER_FREQ_LEN 11 // Must be odd -#define DEFAULT_FILTER_TIME_LEN 3 +#define DEFAULT_FILTER_LEN 3 -static void init_default_filters(srslte_chest_dl_t *q) { +static void set_default_filter(srslte_chest_dl_t *q, int filter_len) { - float f[DEFAULT_FILTER_FREQ_LEN]; - float t[DEFAULT_FILTER_TIME_LEN]; - - for (int i=0;itmp_freqavg = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); - if (!q->tmp_freqavg) { - perror("malloc"); - goto clean_exit; - } - q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); + q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); if (!q->tmp_noise) { perror("malloc"); goto clean_exit; } - q->tmp_timeavg_mult = srslte_vec_malloc(sizeof(cf_t) * 12*cell.nof_prb); - if (!q->tmp_timeavg_mult) { + q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + if (!q->pilot_estimates) { + perror("malloc"); + goto clean_exit; + } + q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + if (!q->pilot_estimates_average) { + perror("malloc"); + goto clean_exit; + } + q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + if (!q->pilot_recv_signal) { perror("malloc"); goto clean_exit; - } - - for (int i=0;ipilot_estimates[i] = srslte_vec_malloc(2*sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i)); - if (!q->pilot_estimates[i]) { - perror("malloc"); - goto clean_exit; - } - q->pilot_recv_signal[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i)); - if (!q->pilot_recv_signal[i]) { - perror("malloc"); - goto clean_exit; - } } if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, SRSLTE_NRE*cell.nof_prb)) { @@ -128,7 +118,14 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell) goto clean_exit; } - init_default_filters(q); + if (srslte_pss_generate(q->pss_signal, cell.id%3)) { + fprintf(stderr, "Error initializing PSS signal for noise estimation\n"); + goto clean_exit; + } + + q->smooth_filter_len = 0; + set_default_filter(q, DEFAULT_FILTER_LEN); + q->cell = cell; } @@ -145,72 +142,62 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q) { srslte_refsignal_cs_free(&q->csr_signal); - if (q->tmp_freqavg) { - free(q->tmp_freqavg); - } if (q->tmp_noise) { free(q->tmp_noise); } - if (q->tmp_timeavg_mult) { - free(q->tmp_timeavg_mult); - } srslte_interp_linear_vector_free(&q->srslte_interp_linvec); srslte_interp_linear_free(&q->srslte_interp_lin); - for (int i=0;ipilot_estimates[i]) { - free(q->pilot_estimates[i]); - } - if (q->pilot_recv_signal[i]) { - free(q->pilot_recv_signal[i]); - } + if (q->pilot_estimates) { + free(q->pilot_estimates); + } + if (q->pilot_estimates_average) { + free(q->pilot_estimates_average); + } + if (q->pilot_recv_signal) { + free(q->pilot_recv_signal); } bzero(q, sizeof(srslte_chest_dl_t)); } -int srslte_chest_dl_set_filter_freq(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) { - if (filter_len <= SRSLTE_CHEST_MAX_FILTER_FREQ_LEN) { - q->filter_freq_len = filter_len; - for (int i=0;ifilter_freq[i] = filter[i]; - } - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR; - } -} - -void srslte_chest_dl_set_filter_time_ema(srslte_chest_dl_t *q, float ema_coefficient) { - q->filter_time_ema = ema_coefficient; -} - -int srslte_chest_dl_set_filter_time(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) { - if (filter_len <= SRSLTE_CHEST_MAX_FILTER_TIME_LEN) { - q->filter_time_len = filter_len; - for (int i=0;ifilter_time[i] = filter[i]; - } - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR; - } -} - - - -#if NOISE_POWER_METHOD==0 /* Uses the difference between the averaged and non-averaged pilot estimates */ -static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *average, cf_t *ce, uint32_t len) { - /* Use difference between averaged and noisy LS pilot estimates */ - srslte_vec_sub_ccc(average, ce, q->tmp_noise, len); - return srslte_vec_avg_power_cf(q->tmp_noise, len); +static float estimate_noise_pilots(srslte_chest_dl_t *q, cf_t *ce, uint32_t port_id) +{ + int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + /* Get averaged pilots from channel estimates */ + srslte_refsignal_cs_get_sf(q->cell, port_id, ce, q->tmp_noise); + /* Substract noisy pilot estimates */ + srslte_vec_sub_ccc(q->tmp_noise, q->pilot_estimates, q->tmp_noise, nref); + /* Compute average power */ + float power = sqrt(2)*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_noise, nref); + return power; } -#endif -#if NOISE_POWER_METHOD==1 +#ifdef ESTIMATE_NOISE_LS_PSS +static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce) +{ + /* Get PSS from received signal */ + srslte_pss_get_slot(input, q->tmp_pss, q->cell.nof_prb, q->cell.cp); + + /* Get channel estimates for PSS position */ + srslte_pss_get_slot(ce, q->tmp_pss_noisy, q->cell.nof_prb, q->cell.cp); + + /* Multiply known PSS by channel estimates */ + srslte_vec_prod_ccc(q->tmp_pss_noisy, q->pss_signal, q->tmp_pss_noisy, SRSLTE_PSS_LEN); + + /* Substract received signal */ + srslte_vec_sub_ccc(q->tmp_pss_noisy, q->tmp_pss, q->tmp_pss_noisy, SRSLTE_PSS_LEN); + + /* Compute average power */ + float power = 2*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_pss_noisy, SRSLTE_PSS_LEN); + return power; +} + + +#else /* Uses the 5 empty transmitted SC before and after the SSS and PSS sequences for noise estimation */ -static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *input) { +static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) { int k_sss = (SRSLTE_CP_NSYMB(q->cell.cp) - 2) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31; float noise_power = 0; noise_power += srslte_vec_avg_power_cf(&input[k_sss-5], 5); // 5 empty SC before SSS @@ -224,48 +211,6 @@ static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *input) { #endif -static void average_estimates(srslte_chest_dl_t *q, cf_t *ce, uint32_t port_id) -{ - int nref=12*q->cell.nof_prb; - uint32_t l, i; - - /* For each symbol with pilots in a slot */ - for (l=0;lcell.cp);l++) { - if (q->filter_freq_len > 0) { - /* Filter pilot estimates in frequency */ - srslte_conv_same_cf(&ce[l*12*q->cell.nof_prb], q->filter_freq, &q->tmp_freqavg[l*12*q->cell.nof_prb], nref, q->filter_freq_len); - } else { - memcpy(&q->tmp_freqavg[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref * sizeof(cf_t)); - } - } - - #if NOISE_POWER_METHOD==0 - q->noise_estimate[port_id] = estimate_noise_port(q, q->tmp_freqavg, ce, - SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)); - #endif - - /* Filter with FIR or don't filter */ - for (l=0;lcell.cp);l++) { - /* Filter in time domain. */ - if (q->filter_time_len > 0) { - /* Multiply symbols by filter and add them */ - bzero(&ce[l*12*q->cell.nof_prb], nref * sizeof(cf_t)); - for (i=0;ifilter_time_len;i++) { - if (l+i-q->filter_time_len/2 < SRSLTE_CP_NSYMB(q->cell.cp) && l+i-q->filter_time_len/2 > 0) { - srslte_vec_sc_prod_cfc(&q->tmp_freqavg[(l+i-q->filter_time_len/2)*12*q->cell.nof_prb], q->filter_time[i], q->tmp_timeavg_mult, nref); - srslte_vec_sum_ccc(q->tmp_timeavg_mult, &ce[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref); - } else { - srslte_vec_sc_prod_cfc(&q->tmp_freqavg[l*12*q->cell.nof_prb], q->filter_time[i], q->tmp_timeavg_mult, nref); - srslte_vec_sum_ccc(q->tmp_timeavg_mult, &ce[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref); - } - } - } else { - memcpy(&ce[l*12*q->cell.nof_prb], &q->tmp_freqavg[l*12*q->cell.nof_prb], nref * sizeof(cf_t)); - } - } -} - - #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id) @@ -285,10 +230,10 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t /* Now interpolate in the time domain between symbols */ if (SRSLTE_CP_ISNORM(q->cell.cp)) { if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(12), 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 2); } else { srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(0), 1); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 6); @@ -299,7 +244,7 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 2); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 2); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), 2); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 2); } else { srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(0), 1); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 5); @@ -308,6 +253,25 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t } } +void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) { + if (filter_len < SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN) { + memcpy(q->smooth_filter, filter, filter_len*sizeof(float)); + q->smooth_filter_len = filter_len; + } else { + fprintf(stderr, "Error setting smoothing filter: filter len exceeds maximum (%d>%d)\n", + filter_len, SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN); + } +} + +static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id) { + uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nref = 2*q->cell.nof_prb; + + for (int l=0;lsmooth_filter, &output[l*nref], nref, q->smooth_filter_len); + } +} + float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) { uint32_t l; @@ -320,43 +284,39 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) return rssi/nsymbols; } -#define RSRP_FROM_ESTIMATES - -float srslte_chest_dl_rsrp(srslte_chest_dl_t *q, uint32_t port_id) { -#ifdef RSRP_FROM_ESTIMATES - return srslte_vec_avg_power_cf(q->pilot_estimates[port_id], - SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); -#else - return srslte_vec_avg_power_cf(q->pilot_estimates_average[port_id], - SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); -#endif -} - int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) { /* Get references from the input signal */ - srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal[port_id]); + srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal); /* Use the known CSR signal to compute Least-squares estimates */ - srslte_vec_prod_conj_ccc(q->pilot_recv_signal[port_id], q->csr_signal.pilots[port_id/2][sf_idx], - q->pilot_estimates[port_id], SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); - + srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_signal.pilots[port_id/2][sf_idx], + q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); if (ce != NULL) { - /* Interpolate to create channel estimates for all resource grid */ - interpolate_pilots(q, q->pilot_estimates[port_id], ce, port_id); + if (q->smooth_filter_len > 0) { + average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id); + interpolate_pilots(q, q->pilot_estimates_average, ce, port_id); + + /* If averaging, compute noise from difference between received and averaged estimates */ + if (sf_idx == 0 || sf_idx == 5) { + q->noise_estimate[port_id] = estimate_noise_pilots(q, ce, port_id); + } + } else { + interpolate_pilots(q, q->pilot_estimates, ce, port_id); + + /* If not averaging, compute noise from empty subcarriers */ + if (sf_idx == 0 || sf_idx == 5) { +#ifdef ESTIMATE_NOISE_LS_PSS + q->noise_estimate[port_id] = estimate_noise_pss(q, input, ce); +#else + q->noise_estimate[port_id] = estimate_noise_empty_sc(q, input); +#endif + } + } + } - /* Average channel estimates */ - average_estimates(q, ce, port_id); - } - - #if NOISE_POWER_METHOD==1 - if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[port_id] = estimate_noise_port(q, input); - } - #endif - /* Compute RSRP for the channel estimates in this port */ - q->rsrp[port_id] = srslte_chest_dl_rsrp(q, port_id); + q->rsrp[port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); if (port_id == 0) { /* compute rssi only for port 0 */ q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id); diff --git a/srslte/lib/ch_estimation/src/refsignal_dl.c b/srslte/lib/ch_estimation/src/refsignal_dl.c index b3fdda616..c0d6767a2 100644 --- a/srslte/lib/ch_estimation/src/refsignal_dl.c +++ b/srslte/lib/ch_estimation/src/refsignal_dl.c @@ -218,10 +218,7 @@ int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, cf_t *pilot } } -/** Copies the RE containing references from an array of subframe symbols into the csr_signal[][]. - * csr_signal[0] is the signal for the first OFDM symbol containing references and csr_signal[1] is the - * second OFDM symbol containing references (symbol 4 or 3 if port_id < 2) - */ +/** Copies the RE containing references from an array of subframe symbols to the pilots array. */ int srslte_refsignal_cs_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_symbols, cf_t *pilots) { uint32_t i, l; diff --git a/srslte/lib/ch_estimation/test/CMakeLists.txt b/srslte/lib/ch_estimation/test/CMakeLists.txt index dd4a77505..4fff63002 100644 --- a/srslte/lib/ch_estimation/test/CMakeLists.txt +++ b/srslte/lib/ch_estimation/test/CMakeLists.txt @@ -37,7 +37,7 @@ ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50) # Downlink MEX libs ######################################################################## -BuildMex(MEXNAME chest SOURCES chest_test_dl_mex.c LIBRARIES srslte) +BuildMex(MEXNAME chest SOURCES chest_test_dl_mex.c LIBRARIES srslte srslte_mex) ######################################################################## diff --git a/srslte/lib/ch_estimation/test/chest_test_dl_mex.c b/srslte/lib/ch_estimation/test/chest_test_dl_mex.c index b1150316c..528278bbb 100644 --- a/srslte/lib/ch_estimation/test/chest_test_dl_mex.c +++ b/srslte/lib/ch_estimation/test/chest_test_dl_mex.c @@ -35,10 +35,7 @@ #define CELLID prhs[0] #define PORTS prhs[1] #define INPUT prhs[2] -#define FREQ_FILTER prhs[3] -#define TIME_FILTER prhs[4] -#define NOF_INPUTS 5 -#define SFIDX prhs[5] +#define NOF_INPUTS 3 void help() { @@ -101,38 +98,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } uint32_t sf_idx=0; - if (nsubframes == 1) { - if (nrhs != NOF_INPUTS+1) { - mexErrMsgTxt("Received 1 subframe. Need to provide subframe index.\n"); - help(); - return; - } - sf_idx = (uint32_t) *((double*) mxGetPr(SFIDX)); - } - if (nrhs > 5) { - uint32_t filter_len = 0; - float *filter; - double *f; - - filter_len = mxGetNumberOfElements(FREQ_FILTER); - filter = malloc(sizeof(float) * filter_len); - f = (double*) mxGetPr(FREQ_FILTER); - for (i=0;i= 1) { plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX); @@ -167,6 +133,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) outi2 = mxGetPi(plhs[2]); } + float noise_power=0; for (int sf=0;sf= 1) { - for (int j=0;j= 2) { - for (int j=0;j= 3) { for (i=0;i= 4) { - plhs[3] = mxCreateDoubleScalar(srslte_chest_dl_get_noise_estimate(&chest)); + plhs[3] = mxCreateDoubleScalar(noise_power); } if (nlhs >= 5) { plhs[4] = mxCreateDoubleScalar(srslte_chest_dl_get_rsrp(&chest)); diff --git a/srslte/lib/fec/src/rm_turbo.c b/srslte/lib/fec/src/rm_turbo.c index b4ed12004..5856a4e46 100644 --- a/srslte/lib/fec/src/rm_turbo.c +++ b/srslte/lib/fec/src/rm_turbo.c @@ -285,7 +285,8 @@ int srslte_rm_turbo_tx_lut(uint8_t *w_buff, uint8_t *systematic, uint8_t *parity } int srslte_rm_turbo_rx_lut(int16_t *input, int16_t *output, uint32_t in_len, uint32_t cb_idx, uint32_t rv_idx) -{ +{ + #ifdef LV_HAVE_AVX return srslte_rm_turbo_rx_lut_avx(input, output, in_len, cb_idx, rv_idx); #else @@ -295,9 +296,7 @@ int srslte_rm_turbo_rx_lut(int16_t *input, int16_t *output, uint32_t in_len, uin if (rv_idx < 4 && cb_idx < SRSLTE_NOF_TC_CB_SIZES) { uint32_t out_len = 3*srslte_cbsegm_cbsize(cb_idx)+12; uint16_t *deinter = deinterleaver[cb_idx][rv_idx]; - - for (int i=0;isymbol_table_qpsk[bits[i]], sizeof(qpsk_packed_t)); } + // Encode last 1, 2 or 3 bit pairs if not multiple of 8 for (int i=0;i<(nbits%8)/2;i++) { - symbols[8*(nbits/8)+i] = q->symbol_table[(bits[8*(nbits/8)]&mask_qpsk[i])>>shift_qpsk[i]]; + symbols[4*(nbits/8)+i] = q->symbol_table[(bits[nbits/8]&mask_qpsk[i])>>shift_qpsk[i]]; } } @@ -78,7 +79,10 @@ void mod_16qam_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint for (int i=0;isymbol_table_16qam[bits[i]], sizeof(qam16_packed_t)); } - symbols[8*(nbits/8)] = q->symbol_table[(bits[8*(nbits/8)]&0xf0)>>4]; + // Encode last 4 bits if not multiple of 8 + if (nbits%8) { + symbols[2*(nbits/8)] = q->symbol_table[(bits[nbits/8]&0xf0)>>4]; + } } void mod_64qam_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint32_t nbits) { @@ -101,22 +105,22 @@ void mod_64qam_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint symbols[i*4+3] = q->symbol_table[in3]; } if (nbits%24 >= 6) { - in80 = bits[24*(nbits/24)+0]; + in80 = bits[3*(nbits/24)+0]; in0 = (in80&0xfc)>>2; - symbols[24*(nbits/24)+0] = q->symbol_table[in0]; + symbols[4*(nbits/24)+0] = q->symbol_table[in0]; } if (nbits%24 >= 12) { - in81 = bits[24*(nbits/24)+1]; + in81 = bits[3*(nbits/24)+1]; in1 = (in80&0x03)<<4 | ((in81&0xf0)>>4); - symbols[24*(nbits/24)+1] = q->symbol_table[in1]; + symbols[4*(nbits/24)+1] = q->symbol_table[in1]; } if (nbits%24 >= 18) { - in82 = bits[24*(nbits/24)+2]; + in82 = bits[3*(nbits/24)+2]; in2 = (in81&0x0f)<<2 | ((in82&0xc0)>>6); - symbols[24*(nbits/24)+2] = q->symbol_table[in2]; + symbols[4*(nbits/24)+2] = q->symbol_table[in2]; } } diff --git a/srslte/lib/phch/src/pdsch.c b/srslte/lib/phch/src/pdsch.c index 2bfb5090f..3e6670a84 100644 --- a/srslte/lib/phch/src/pdsch.c +++ b/srslte/lib/phch/src/pdsch.c @@ -425,7 +425,7 @@ int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, * thus we don't need tot set it in the LLRs normalization */ srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); - + /* descramble */ if (rnti != q->rnti) { srslte_sequence_t seq; @@ -522,10 +522,10 @@ int srslte_pdsch_encode_rnti(srslte_pdsch_t *q, if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; } - srslte_scrambling_bytes_offset(&seq, (uint8_t*) q->e, 0, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&seq, (uint8_t*) q->e, cfg->nbits.nof_bits); srslte_sequence_free(&seq); } else { - srslte_scrambling_bytes_offset(&q->seq[cfg->sf_idx], (uint8_t*) q->e, 0, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&q->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits.nof_bits); } srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e, q->d, cfg->nbits.nof_bits); diff --git a/srslte/lib/phch/src/pusch.c b/srslte/lib/phch/src/pusch.c index 9dcc784c6..b9231f577 100644 --- a/srslte/lib/phch/src/pusch.c +++ b/srslte/lib/phch/src/pusch.c @@ -527,10 +527,10 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; } - srslte_scrambling_bytes_offset(&seq, (uint8_t*) q->q, 0, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&seq, (uint8_t*) q->q, cfg->nbits.nof_bits); srslte_sequence_free(&seq); } else { - srslte_scrambling_bytes_offset(&q->seq[cfg->sf_idx], (uint8_t*) q->q, 0, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&q->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits); } // Correct UCI placeholder bits diff --git a/srslte/lib/phch/src/sch.c b/srslte/lib/phch/src/sch.c index 846295d49..134b73789 100644 --- a/srslte/lib/phch/src/sch.c +++ b/srslte/lib/phch/src/sch.c @@ -390,7 +390,6 @@ static int decode_tb(srslte_sch_t *q, n_e = Qm * ((uint32_t) ceilf((float) Gp/cb_segm->C)); } - bzero(softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t)); /* Rate Unmatching */ if (srslte_rm_turbo_rx_lut(&e_bits[rp], softbuffer->buffer_f[i], n_e, cblen_idx, rv)) { fprintf(stderr, "Error in rate matching\n"); diff --git a/srslte/lib/phch/test/dlsch_encode_test_mex.c b/srslte/lib/phch/test/dlsch_encode_test_mex.c index 04ccb69e0..8c2318583 100644 --- a/srslte/lib/phch/test/dlsch_encode_test_mex.c +++ b/srslte/lib/phch/test/dlsch_encode_test_mex.c @@ -108,6 +108,15 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexErrMsgTxt("Error computing CB segmentation\n"); return; } + uint32_t tmp_rv=cfg.rv; + if (tmp_rv) { + cfg.rv = 0; + if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) { + mexErrMsgTxt("Error encoding TB\n"); + return; + } + cfg.rv = tmp_rv; + } if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) { mexErrMsgTxt("Error encoding TB\n"); return; diff --git a/srslte/lib/phch/test/pdsch_test.c b/srslte/lib/phch/test/pdsch_test.c index a8b8e87e5..84955d921 100644 --- a/srslte/lib/phch/test/pdsch_test.c +++ b/srslte/lib/phch/test/pdsch_test.c @@ -118,14 +118,6 @@ cf_t *slot_symbols[SRSLTE_MAX_PORTS]; srslte_pdsch_t pdsch; srslte_ofdm_t ofdm_tx, ofdm_rx; -int dummy_function() { -#ifdef DO_OFDM - srslte_ofdm_rx_sf(&ofdm_rx, sf_symbols, slot_symbols[1]); -#endif - srslte_softbuffer_rx_reset_tbs(&softbuffer_rx, grant.mcs.tbs); - return srslte_pdsch_decode(&pdsch, &pdsch_cfg, &softbuffer_rx, slot_symbols[0], ce, 0, data); -} - int main(int argc, char **argv) { uint32_t i, j; int ret = -1; @@ -228,38 +220,53 @@ int main(int argc, char **argv) { for (i=0;i 0) { - slot_symbols[0][j] += slot_symbols[i][j]; - } - ce[i][j] = 1; - } + if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer_tx, data, slot_symbols)) { + fprintf(stderr, "Error encoding PDSCH\n"); + goto quit; } - + } + + /* combine outputs */ + for (i=0;i 0) { + slot_symbols[0][j] += slot_symbols[i][j]; + } + ce[i][j] = 1; + } + } + #ifdef DO_OFDM - srslte_ofdm_tx_sf(&ofdm_tx, slot_symbols[0], sf_symbols); + srslte_ofdm_tx_sf(&ofdm_tx, slot_symbols[0], sf_symbols); #endif - } } int M=1; int r=0; srslte_sch_set_max_noi(&pdsch.dl_sch, 10); gettimeofday(&t[1], NULL); for (i=0;i NOF_INPUTS) { cf_t *cearray = NULL; - nof_re = mexutils_read_cf(prhs[NOF_INPUTS], &cearray); + int nof_re = mexutils_read_cf(prhs[NOF_INPUTS], &cearray); cf_t *cearray_ptr = cearray; for (i=0;i NOF_INPUTS + 1) { noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); } else { - noise_power = 0; + noise_power = srslte_chest_dl_get_noise_estimate(&chest); } uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8); diff --git a/srslte/lib/resampling/src/interp.c b/srslte/lib/resampling/src/interp.c index f602d5cc4..dfdeab7c3 100644 --- a/srslte/lib/resampling/src/interp.c +++ b/srslte/lib/resampling/src/interp.c @@ -123,12 +123,21 @@ void srslte_interp_linear_vector_free(srslte_interp_linsrslte_vec_t *q) { } void srslte_interp_linear_vector(srslte_interp_linsrslte_vec_t *q, cf_t *in0, cf_t *in1, cf_t *between, uint32_t M) +{ + srslte_interp_linear_vector2(q, in0, in1, NULL, between, M); +} + +void srslte_interp_linear_vector2(srslte_interp_linsrslte_vec_t *q, cf_t *in0, cf_t *in1, cf_t *start, cf_t *between, uint32_t M) { uint32_t i; srslte_vec_sub_ccc(in1, in0, q->diff_vec, q->vector_len); - srslte_vec_sc_prod_cfc(q->diff_vec, (float) 1/M, q->diff_vec, q->vector_len); - srslte_vec_sum_ccc(in0, q->diff_vec, between, q->vector_len); + srslte_vec_sc_prod_cfc(q->diff_vec, (float) 1/(M+1), q->diff_vec, q->vector_len); + if (start) { + srslte_vec_sum_ccc(start, q->diff_vec, between, q->vector_len); + } else { + srslte_vec_sum_ccc(in0, q->diff_vec, between, q->vector_len); + } for (i=0;idiff_vec, &between[q->vector_len], q->vector_len); between += q->vector_len; @@ -193,7 +202,7 @@ void srslte_interp_linear_offset(srslte_interp_lin_t *q, cf_t *input, cf_t *outp i=0; for (j=0;jM; + output[off_st-j-1] = input[i] - (j+1) * (input[i+1]-input[i]) / q->M; } srslte_vec_sub_ccc(&input[1], input, q->diff_vec, (q->vector_len-1)); srslte_vec_sc_prod_cfc(q->diff_vec, (float) 1/q->M, q->diff_vec, q->vector_len-1); diff --git a/srslte/lib/scrambling/src/scrambling.c b/srslte/lib/scrambling/src/scrambling.c index 2e21db482..f8f423ffb 100644 --- a/srslte/lib/scrambling/src/scrambling.c +++ b/srslte/lib/scrambling/src/scrambling.c @@ -28,6 +28,7 @@ #include #include #include +#include "srslte/utils/bit.h" #include "srslte/utils/vector.h" #include "srslte/scrambling/scrambling.h" @@ -58,47 +59,47 @@ void srslte_scrambling_c_offset(srslte_sequence_t *s, cf_t *data, int offset, in srslte_vec_prod_cfc(data, &s->c_float[offset], data, len); } -void scrambling_b(uint8_t *c, uint8_t *data, int offset, int len) { - int i; - // Do XOR on a word basis - - if (!(len%8)) { - uint64_t *x = (uint64_t*) data; - uint64_t *y = (uint64_t*) &c[offset]; - for (int i=0;ic, data, 0, s->len); + scrambling_b_word(s->c, data, s->len); } void srslte_scrambling_b_offset(srslte_sequence_t *s, uint8_t *data, int offset, int len) { - scrambling_b(s->c, data, offset, len); + if (offset%8) { + // Do not load words if offset is not word-aligned + scrambling_b(&s->c[offset], data, len); + } else { + scrambling_b_word(&s->c[offset], data, len); + } } -void srslte_scrambling_bytes(srslte_sequence_t *s, uint8_t *data) { - scrambling_b(s->c_bytes, data, 0, s->len/8); -} - -void srslte_scrambling_bytes_offset(srslte_sequence_t *s, uint8_t *data, int offset, int len) { - scrambling_b(s->c_bytes, data, offset, len/8); +void srslte_scrambling_bytes(srslte_sequence_t *s, uint8_t *data, int len) { + scrambling_b_word(s->c_bytes, data, len/8); + // Scramble last bits + if (len%8) { + uint8_t tmp_bits[8]; + srslte_bit_unpack_vector(&data[len/8], tmp_bits, len%8); + scrambling_b(&s->c[8*(len/8)], tmp_bits, len%8); + srslte_bit_pack_vector(tmp_bits, &data[len/8], len%8); + } } diff --git a/srslte/lib/sync/src/pss.c b/srslte/lib/sync/src/pss.c index 77587bae2..76ab9534e 100644 --- a/srslte/lib/sync/src/pss.c +++ b/srslte/lib/sync/src/pss.c @@ -254,6 +254,12 @@ void srslte_pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, srslte_ memset(&slot[k + SRSLTE_PSS_LEN], 0, 5 * sizeof(cf_t)); } +void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp) { + int k; + k = (SRSLTE_CP_NSYMB(cp) - 1) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; + memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); +} + /** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ diff --git a/srslte/lib/ue/src/ue_dl.c b/srslte/lib/ue/src/ue_dl.c index a9dd8a968..e0d167064 100644 --- a/srslte/lib/ue/src/ue_dl.c +++ b/srslte/lib/ue/src/ue_dl.c @@ -39,8 +39,6 @@ #define MAX_CANDIDATES 64 -#define PDSCH_DO_ZF - srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}; // SRSLTE_DCI_FORMAT1B should go here also const uint32_t nof_ue_formats = 2; @@ -227,11 +225,9 @@ int srslte_ue_dl_decode_rnti_rv_packet(srslte_ue_dl_t *q, srslte_ra_dl_grant_t * srslte_softbuffer_rx_reset(&q->softbuffer); } -#ifdef PDSCH_DO_ZF - float noise_estimate = 0; -#else + // Uncoment next line to do ZF by default in pdsch_ue example + //float noise_estimate = 0; float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); -#endif if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { ret = srslte_pdsch_decode_rnti(&q->pdsch, &q->pdsch_cfg, &q->softbuffer,