mirror of https://github.com/pvnis/srsRAN_4G.git
DMRS PUSCH estimation working and tested
parent
00c2083c1b
commit
d622d5d19d
@ -0,0 +1,184 @@
|
|||||||
|
%% LTE Downlink Channel Estimation and Equalization
|
||||||
|
|
||||||
|
%% Cell-Wide Settings
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
plot_noise_estimation_only=false;
|
||||||
|
|
||||||
|
SNR_values_db=linspace(0,30,5);
|
||||||
|
Nrealizations=1;
|
||||||
|
|
||||||
|
w1=1/3;
|
||||||
|
|
||||||
|
%% UE Configuration
|
||||||
|
ue = lteRMCUL('A3-5');
|
||||||
|
ue.TotSubframes = 2;
|
||||||
|
|
||||||
|
K=ue.NULRB*12;
|
||||||
|
P=K/6;
|
||||||
|
|
||||||
|
%% Channel Model Configuration
|
||||||
|
chs.Seed = 1; % Random channel seed
|
||||||
|
chs.InitTime = 0;
|
||||||
|
chs.NRxAnts = 1; % 1 receive antenna
|
||||||
|
chs.DelayProfile = 'EVA';
|
||||||
|
chs.DopplerFreq = 300; % 120Hz Doppler frequency
|
||||||
|
chs.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation
|
||||||
|
chs.NTerms = 16; % Oscillators used in fading model
|
||||||
|
chs.ModelType = 'GMEDS'; % Rayleigh fading model type
|
||||||
|
chs.InitPhase = 'Random'; % Random initial phases
|
||||||
|
chs.NormalizePathGains = 'On'; % Normalize delay profile power
|
||||||
|
chs.NormalizeTxAnts = 'On'; % Normalize for transmit antennas
|
||||||
|
|
||||||
|
%% Channel Estimator Configuration
|
||||||
|
cec = struct; % Channel estimation config structure
|
||||||
|
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 = 'Causal'; % Interpolation window type
|
||||||
|
cec.InterpWinSize = 1; % Interpolation window size
|
||||||
|
|
||||||
|
|
||||||
|
%% Allocate memory
|
||||||
|
Ntests=3;
|
||||||
|
hest=cell(1,Ntests);
|
||||||
|
for i=1:Ntests
|
||||||
|
hest{i}=zeros(K,14);
|
||||||
|
end
|
||||||
|
MSE=zeros(Ntests,Nrealizations,length(SNR_values_db));
|
||||||
|
noiseEst=zeros(Ntests,Nrealizations,length(SNR_values_db));
|
||||||
|
|
||||||
|
legends={'matlab','ls',num2str(w1)};
|
||||||
|
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
|
||||||
|
|
||||||
|
%% Signal Generation
|
||||||
|
[txWaveform, txGrid, info] = lteRMCULTool(ue,[1;0;0;1]);
|
||||||
|
|
||||||
|
%% 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
|
||||||
|
|
||||||
|
chs.SamplingRate = info.SamplingRate;
|
||||||
|
[rxWaveform, chinfo] = lteFadingChannel(chs,txWaveform);
|
||||||
|
|
||||||
|
%% Additive Noise
|
||||||
|
|
||||||
|
% Calculate noise gain
|
||||||
|
N0 = 1/(sqrt(2.0*double(info.Nfft))*SNR);
|
||||||
|
|
||||||
|
% Create additive white Gaussian noise
|
||||||
|
noise = N0*complex(randn(size(rxWaveform)),randn(size(rxWaveform)));
|
||||||
|
|
||||||
|
% Add noise to the received time domain waveform
|
||||||
|
rxWaveform = rxWaveform + noise;
|
||||||
|
|
||||||
|
%% Synchronization
|
||||||
|
|
||||||
|
% Time offset estimation is done once because depends on channel
|
||||||
|
% model only
|
||||||
|
if (offset==-1)
|
||||||
|
offset = lteULFrameOffset(ue,ue.PUSCH,rxWaveform);
|
||||||
|
end
|
||||||
|
rxWaveform = rxWaveform(1+offset:end);
|
||||||
|
|
||||||
|
%% OFDM Demodulation
|
||||||
|
rxGrid = lteSCFDMADemodulate(ue,rxWaveform);
|
||||||
|
rxGrid = rxGrid(:,1:14);
|
||||||
|
|
||||||
|
%% Perfect channel estimate
|
||||||
|
h=lteULPerfectChannelEstimate(ue,chs,offset);
|
||||||
|
h=h(:,1:14);
|
||||||
|
|
||||||
|
%% Channel Estimation with Matlab
|
||||||
|
[hest{1}, noiseEst(1,nreal,snr_idx)] = lteULChannelEstimate(ue,ue.PUSCH,cec,rxGrid);
|
||||||
|
|
||||||
|
%% LS-Linear estimation with srsLTE
|
||||||
|
[hest{2}, noiseEst(2,nreal,snr_idx)] = srslte_chest_ul(ue,ue.PUSCH,rxGrid);
|
||||||
|
|
||||||
|
%% LS-Linear estimation + averaging with srsLTE
|
||||||
|
[hest{3}, noiseEst(3,nreal,snr_idx)] = srslte_chest_ul(ue,ue.PUSCH,rxGrid,w1);
|
||||||
|
|
||||||
|
%% Compute MSE
|
||||||
|
for i=1:Ntests
|
||||||
|
MSE(i,nreal,snr_idx)=mean(mean(abs(h-hest{i}).^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(1,1,1)
|
||||||
|
sym=1;
|
||||||
|
n=1:(K*length(sym));
|
||||||
|
for i=1:Ntests
|
||||||
|
plot(n,abs(reshape(hest{i}(:,sym),1,[])),colors2{i});
|
||||||
|
hold on;
|
||||||
|
end
|
||||||
|
plot(n,abs(reshape(h(:,sym),1,[])),'k');
|
||||||
|
hold off;
|
||||||
|
|
||||||
|
tmp=cell(Ntests+1,1);
|
||||||
|
for i=1:Ntests
|
||||||
|
tmp{i}=legends{i};
|
||||||
|
end
|
||||||
|
tmp{Ntests+1}='Perfect';
|
||||||
|
legend(tmp)
|
||||||
|
|
||||||
|
xlabel('SNR (dB)')
|
||||||
|
ylabel('Channel Gain')
|
||||||
|
grid on;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% Compute average MSE and noise estimation
|
||||||
|
mean_mse=mean(MSE,2);
|
||||||
|
mean_snr=10*log10(1./mean(noiseEst,2));
|
||||||
|
|
||||||
|
%disp(mean_snr(3)
|
||||||
|
|
||||||
|
%% Plot average over all SNR values
|
||||||
|
if (length(SNR_values_db) > 1)
|
||||||
|
subplot(1,2,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
|
||||||
|
xlabel('SNR (dB)')
|
||||||
|
ylabel('Estimated SNR (dB)')
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,253 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include "srslte/srslte.h"
|
||||||
|
|
||||||
|
srslte_cell_t cell = {
|
||||||
|
6, // nof_prb
|
||||||
|
1, // nof_ports
|
||||||
|
0,
|
||||||
|
1000, // cell_id
|
||||||
|
SRSLTE_CP_NORM // cyclic prefix
|
||||||
|
};
|
||||||
|
|
||||||
|
char *output_matlab = NULL;
|
||||||
|
|
||||||
|
void usage(char *prog) {
|
||||||
|
printf("Usage: %s [recov]\n", prog);
|
||||||
|
|
||||||
|
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb);
|
||||||
|
printf("\t-e extended cyclic prefix [Default normal]\n");
|
||||||
|
|
||||||
|
printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id);
|
||||||
|
|
||||||
|
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
|
||||||
|
printf("\t-v increase verbosity\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_args(int argc, char **argv) {
|
||||||
|
int opt;
|
||||||
|
while ((opt = getopt(argc, argv, "recov")) != -1) {
|
||||||
|
switch(opt) {
|
||||||
|
case 'r':
|
||||||
|
cell.nof_prb = atoi(argv[optind]);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
cell.cp = SRSLTE_CP_EXT;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
cell.id = atoi(argv[optind]);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
output_matlab = argv[optind];
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
srslte_verbose++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
srslte_chest_ul_t est;
|
||||||
|
cf_t *input = NULL, *ce = NULL, *h = NULL;
|
||||||
|
int i, j, n_port=0, sf_idx=0, cid=0, num_re;
|
||||||
|
int ret = -1;
|
||||||
|
int max_cid;
|
||||||
|
FILE *fmatlab = NULL;
|
||||||
|
|
||||||
|
parse_args(argc,argv);
|
||||||
|
|
||||||
|
if (output_matlab) {
|
||||||
|
fmatlab=fopen(output_matlab, "w");
|
||||||
|
if (!fmatlab) {
|
||||||
|
perror("fopen");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
num_re = 2 * cell.nof_prb * SRSLTE_NRE * SRSLTE_CP_NSYMB(cell.cp);
|
||||||
|
|
||||||
|
input = srslte_vec_malloc(num_re * sizeof(cf_t));
|
||||||
|
if (!input) {
|
||||||
|
perror("srslte_vec_malloc");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
h = srslte_vec_malloc(num_re * sizeof(cf_t));
|
||||||
|
if (!h) {
|
||||||
|
perror("srslte_vec_malloc");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
ce = srslte_vec_malloc(num_re * sizeof(cf_t));
|
||||||
|
if (!ce) {
|
||||||
|
perror("srslte_vec_malloc");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell.id == 1000) {
|
||||||
|
cid = 0;
|
||||||
|
max_cid = 504;
|
||||||
|
} else {
|
||||||
|
cid = cell.id;
|
||||||
|
max_cid = cell.id;
|
||||||
|
}
|
||||||
|
printf("max_cid=%d, cid=%d, cell.id=%d\n", max_cid, cid, cell.id);
|
||||||
|
while(cid <= max_cid) {
|
||||||
|
cell.id = cid;
|
||||||
|
if (srslte_chest_ul_init(&est, cell)) {
|
||||||
|
fprintf(stderr, "Error initializing equalizer\n");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int n=6;n<=cell.nof_prb;n+=5) {
|
||||||
|
if (srslte_dft_precoding_valid_prb(n)) {
|
||||||
|
for (int delta_ss=29;delta_ss<SRSLTE_NOF_DELTA_SS;delta_ss++) {
|
||||||
|
for (int cshift=7;cshift<SRSLTE_NOF_CSHIFT;cshift++) {
|
||||||
|
for (int t=2;t<3;t++) {
|
||||||
|
|
||||||
|
/* Setup and pregen DMRS reference signals */
|
||||||
|
srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg;
|
||||||
|
|
||||||
|
uint32_t nof_prb = n;
|
||||||
|
pusch_cfg.cyclic_shift = cshift;
|
||||||
|
pusch_cfg.delta_ss = delta_ss;
|
||||||
|
bool group_hopping_en = false;
|
||||||
|
bool sequence_hopping_en = false;
|
||||||
|
|
||||||
|
if (!t) {
|
||||||
|
group_hopping_en = false;
|
||||||
|
sequence_hopping_en = false;
|
||||||
|
} else if (t == 1) {
|
||||||
|
group_hopping_en = false;
|
||||||
|
sequence_hopping_en = true;
|
||||||
|
} else if (t == 2) {
|
||||||
|
group_hopping_en = true;
|
||||||
|
sequence_hopping_en = false;
|
||||||
|
}
|
||||||
|
pusch_cfg.group_hopping_en = group_hopping_en;
|
||||||
|
pusch_cfg.sequence_hopping_en = sequence_hopping_en;
|
||||||
|
srslte_chest_ul_set_cfg(&est, &pusch_cfg, NULL, NULL);
|
||||||
|
|
||||||
|
// Loop through subframe idx and cyclic shifts
|
||||||
|
|
||||||
|
for (int sf_idx=0;sf_idx<10;sf_idx+=3) {
|
||||||
|
for (int cshift_dmrs=0;cshift_dmrs<SRSLTE_NOF_CSHIFT;cshift_dmrs+=5) {
|
||||||
|
|
||||||
|
|
||||||
|
if (SRSLTE_VERBOSE_ISINFO()) {
|
||||||
|
printf("nof_prb: %d, ",nof_prb);
|
||||||
|
printf("cyclic_shift: %d, ",pusch_cfg.cyclic_shift);
|
||||||
|
printf("cyclic_shift_for_dmrs: %d, ", cshift_dmrs);
|
||||||
|
printf("delta_ss: %d, ",pusch_cfg.delta_ss);
|
||||||
|
printf("SF_idx: %d\n", sf_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate random input */
|
||||||
|
bzero(input, sizeof(cf_t) * num_re);
|
||||||
|
for (i=0;i<num_re;i++) {
|
||||||
|
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate channel and pass input through channel */
|
||||||
|
for (i=0;i<2*SRSLTE_CP_NSYMB(cell.cp);i++) {
|
||||||
|
for (j=0;j<cell.nof_prb * SRSLTE_NRE;j++) {
|
||||||
|
float x = -1+(float) i/SRSLTE_CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/SRSLTE_NRE);
|
||||||
|
h[i*cell.nof_prb * SRSLTE_NRE+j] = (3+x) * cexpf(I * x);
|
||||||
|
input[i*cell.nof_prb * SRSLTE_NRE+j] *= h[i*cell.nof_prb * SRSLTE_NRE+j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimate channel
|
||||||
|
uint32_t prb_idx[2]= {0, 0};
|
||||||
|
srslte_chest_ul_estimate(&est, input, ce, n, sf_idx, cshift_dmrs, prb_idx);
|
||||||
|
|
||||||
|
// Compute MSE
|
||||||
|
float mse = 0;
|
||||||
|
for (i=0;i<num_re;i++) {
|
||||||
|
mse += cabsf(ce[i]-h[i]);
|
||||||
|
}
|
||||||
|
mse /= num_re;
|
||||||
|
INFO("MSE: %f\n", mse);
|
||||||
|
if (mse > 4) {
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cid+=10;
|
||||||
|
printf("cid=%d\n", cid);
|
||||||
|
srslte_chest_ul_free(&est);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (fmatlab) {
|
||||||
|
fprintf(fmatlab, "input=");
|
||||||
|
srslte_vec_fprint_c(fmatlab, input, num_re);
|
||||||
|
fprintf(fmatlab, ";\n");
|
||||||
|
fprintf(fmatlab, "h=");
|
||||||
|
srslte_vec_fprint_c(fmatlab, h, num_re);
|
||||||
|
fprintf(fmatlab, ";\n");
|
||||||
|
fprintf(fmatlab, "ce=");
|
||||||
|
srslte_vec_fprint_c(fmatlab, ce, num_re);
|
||||||
|
fprintf(fmatlab, ";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
do_exit:
|
||||||
|
|
||||||
|
if (ce) {
|
||||||
|
free(ce);
|
||||||
|
}
|
||||||
|
if (input) {
|
||||||
|
free(input);
|
||||||
|
}
|
||||||
|
if (h) {
|
||||||
|
free(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
printf("OK\n");
|
||||||
|
} else {
|
||||||
|
printf("Error at cid=%d, slot=%d, port=%d\n",cid, sf_idx, n_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(ret);
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsLTE library.
|
||||||
|
*
|
||||||
|
* srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsLTE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "srslte/srslte.h"
|
||||||
|
#include "srslte/mex/mexutils.h"
|
||||||
|
|
||||||
|
|
||||||
|
/** MEX function to be called from MATLAB to test the channel estimator
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define UECFG prhs[0]
|
||||||
|
#define PUSCHCFG prhs[1]
|
||||||
|
#define INPUT prhs[2]
|
||||||
|
#define NOF_INPUTS 3
|
||||||
|
|
||||||
|
void help()
|
||||||
|
{
|
||||||
|
mexErrMsgTxt
|
||||||
|
("[estChannel, noiseEst, eq_output] = srslte_chest_ul(ue_cfg, pusch_cfg, inputSignal, [w_coeff])\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the gateway function */
|
||||||
|
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||||
|
{
|
||||||
|
|
||||||
|
srslte_cell_t cell;
|
||||||
|
srslte_chest_ul_t chest;
|
||||||
|
|
||||||
|
cf_t *input_signal = NULL, *output_signal = NULL;
|
||||||
|
cf_t *ce = NULL;
|
||||||
|
|
||||||
|
if (nrhs < NOF_INPUTS) {
|
||||||
|
help();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 NCellID not found in UE config\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cell.cp = SRSLTE_CP_NORM;
|
||||||
|
cell.nof_ports = 1;
|
||||||
|
|
||||||
|
uint32_t sf_idx=0;
|
||||||
|
if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) {
|
||||||
|
help();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg;
|
||||||
|
pusch_cfg.group_hopping_en = false;
|
||||||
|
pusch_cfg.sequence_hopping_en = false;
|
||||||
|
char *tmp = mexutils_get_char_struct(UECFG, "Hopping");
|
||||||
|
if (tmp) {
|
||||||
|
if (!strcmp(tmp, "Group")) {
|
||||||
|
pusch_cfg.group_hopping_en = true;
|
||||||
|
} else if (!strcmp(tmp, "Sequence")) {
|
||||||
|
pusch_cfg.sequence_hopping_en = true;
|
||||||
|
}
|
||||||
|
mxFree(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (mexutils_read_uint32_struct(UECFG, "SeqGroup", &pusch_cfg.delta_ss)) {
|
||||||
|
pusch_cfg.delta_ss = 0;
|
||||||
|
}
|
||||||
|
if (mexutils_read_uint32_struct(UECFG, "CyclicShift", &pusch_cfg.cyclic_shift)) {
|
||||||
|
pusch_cfg.cyclic_shift = 0;
|
||||||
|
}
|
||||||
|
float *prbset;
|
||||||
|
mxArray *p;
|
||||||
|
p = mxGetField(PUSCHCFG, 0, "PRBSet");
|
||||||
|
if (!p) {
|
||||||
|
mexErrMsgTxt("Error field PRBSet not found in PUSCH config\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t nof_prb = mexutils_read_f(p, &prbset);
|
||||||
|
uint32_t n_prb[2];
|
||||||
|
n_prb[0] = prbset[0];
|
||||||
|
n_prb[1] = prbset[0];
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t cyclic_shift_for_dmrs = 0;
|
||||||
|
if (mexutils_read_uint32_struct(PUSCHCFG, "DynCyclicShift", &cyclic_shift_for_dmrs)) {
|
||||||
|
cyclic_shift_for_dmrs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srslte_chest_ul_init(&chest, cell)) {
|
||||||
|
mexErrMsgTxt("Error initiating channel estimator\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
srslte_chest_ul_set_cfg(&chest, &pusch_cfg, NULL, NULL);
|
||||||
|
|
||||||
|
/** Allocate input buffers */
|
||||||
|
int nof_re = 2*SRSLTE_CP_NSYMB(cell.cp)*cell.nof_prb*SRSLTE_NRE;
|
||||||
|
ce = srslte_vec_malloc(nof_re * sizeof(cf_t));
|
||||||
|
output_signal = srslte_vec_malloc(nof_re * sizeof(cf_t));
|
||||||
|
|
||||||
|
// Read input signal
|
||||||
|
int insignal_len = mexutils_read_cf(INPUT, &input_signal);
|
||||||
|
if (insignal_len < 0) {
|
||||||
|
mexErrMsgTxt("Error reading input signal\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read optional value smooth filter coefficient
|
||||||
|
if (nrhs > NOF_INPUTS) {
|
||||||
|
float w = (float) mxGetScalar(prhs[NOF_INPUTS]);
|
||||||
|
srslte_chest_ul_set_smooth_filter3_coeff(&chest, w);
|
||||||
|
} else {
|
||||||
|
srslte_chest_ul_set_smooth_filter(&chest, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform channel estimation
|
||||||
|
if (srslte_chest_ul_estimate(&chest, input_signal, ce, nof_prb, sf_idx, cyclic_shift_for_dmrs, n_prb)) {
|
||||||
|
mexErrMsgTxt("Error running channel estimator\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get noise power estimation
|
||||||
|
float noise_power = srslte_chest_ul_get_noise_estimate(&chest);
|
||||||
|
|
||||||
|
// Perform channel equalization
|
||||||
|
srslte_predecoding_single(input_signal, ce, output_signal, nof_re, noise_power);
|
||||||
|
|
||||||
|
/* Write output values */
|
||||||
|
if (nlhs >= 1) {
|
||||||
|
mexutils_write_cf(ce, &plhs[0], mxGetM(INPUT), mxGetN(INPUT));
|
||||||
|
}
|
||||||
|
if (nlhs >= 2) {
|
||||||
|
plhs[1] = mxCreateDoubleScalar(noise_power);
|
||||||
|
}
|
||||||
|
if (nlhs >= 3) {
|
||||||
|
mexutils_write_cf(output_signal, &plhs[2], mxGetM(INPUT), mxGetN(INPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free all memory
|
||||||
|
srslte_chest_ul_free(&chest);
|
||||||
|
|
||||||
|
if (ce) {
|
||||||
|
free(ce);
|
||||||
|
}
|
||||||
|
if (input_signal) {
|
||||||
|
free(input_signal);
|
||||||
|
}
|
||||||
|
if (output_signal) {
|
||||||
|
free(output_signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue