DMRS PUSCH estimation working and tested

master
Ismael Gomez 9 years ago
parent 00c2083c1b
commit d622d5d19d

@ -6,8 +6,8 @@ clear
plot_noise_estimation_only=false; plot_noise_estimation_only=false;
SNR_values_db=linspace(0,30,5); SNR_values_db=100;%linspace(0,30,5);
Nrealizations=4; Nrealizations=1;
w1=0.1; w1=0.1;
w2=0.2; w2=0.2;
@ -57,8 +57,10 @@ Ports = gridsize(3); % Number of transmit antenna ports
%% Allocate memory %% Allocate memory
Ntests=4; Ntests=4;
hest=cell(1,Ntests); hest=cell(1,Ntests);
tmpnoise=cell(1,Ntests);
for i=1:Ntests for i=1:Ntests
hest{i}=zeros(K,140); hest{i}=zeros(K,140);
tmpnoise{i}=zeros(1,10);
end end
hls=zeros(4,4*P*10); hls=zeros(4,4*P*10);
MSE=zeros(Ntests,Nrealizations,length(SNR_values_db)); MSE=zeros(Ntests,Nrealizations,length(SNR_values_db));
@ -173,27 +175,31 @@ rxGrid_nonoise = rxGrid_nonoise(:,1:140);
% True channel % True channel
h=rxGrid_nonoise./(txGrid); h=rxGrid_nonoise./(txGrid);
%% Channel Estimation with Matlab
tmpnoise=zeros(10,1);
for i=1:10 for i=1:10
enb.NSubframe=i-1; 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)); rxGrid_sf = rxGrid(:,(i-1)*14+1:i*14);
end
noiseEst(1,nreal,snr_idx)=mean(tmpnoise)*sqrt(2)*enb.CellRefP; %% Channel Estimation with Matlab
[hest{1}(:,(1:14)+(i-1)*14), tmpnoise{1}(i), hls(:,(1:4*P)+(i-1)*4*P)] = ...
lteDLChannelEstimate2(enb,cec,rxGrid_sf);
tmpnoise{1}(i)=tmpnoise{1}(i)*sqrt(2)*enb.CellRefP;
%% LS-Linear estimation with srsLTE %% LS-Linear estimation with srsLTE
[tmp, ~, ~, noiseEst(2,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid); [hest{2}(:,(1:14)+(i-1)*14), tmpnoise{2}(i)] = srslte_chest_dl(enb,rxGrid_sf);
hest{2}=reshape(tmp, size(hest{1}));
%% LS-Linear + averaging with srsLTE %% LS-Linear + averaging with srsLTE
[tmp, ~, ~, noiseEst(3,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid,w1); [hest{3}(:,(1:14)+(i-1)*14), tmpnoise{3}(i)] = srslte_chest_dl(enb,rxGrid_sf,w1);
hest{3}=reshape(tmp, size(hest{1}));
%% LS-Linear + more averaging with srsLTE %% LS-Linear + more averaging with srsLTE
[tmp, ~, ~, noiseEst(4,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid,w2); [hest{4}(:,(1:14)+(i-1)*14), tmpnoise{4}(i)] = srslte_chest_dl(enb,rxGrid_sf,w2);
hest{4}=reshape(tmp, size(hest{1}));
end
%% Average noise estimates over all frame
for i=1:Ntests
noiseEst(i,nreal,snr_idx)=mean(tmpnoise{i});
end
%% Compute MSE %% Compute MSE
for i=1:Ntests for i=1:Ntests
@ -203,7 +209,6 @@ end
%% Plot a single realization %% Plot a single realization
if (length(SNR_values_db) == 1) if (length(SNR_values_db) == 1)
subplot(2,1,1)
sym=1; sym=1;
ref_idx=1:P; ref_idx=1:P;
ref_idx_x=[1:6:K];% (292:6:360)-216];% 577:6:648]; ref_idx_x=[1:6:K];% (292:6:360)-216];% 577:6:648];
@ -228,9 +233,6 @@ if (length(SNR_values_db) == 1)
fprintf('Mean MMSE Robust %.2f dB\n', 10*log10(MSE(4,nreal,snr_idx))) 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))) 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 end

@ -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

@ -27,6 +27,7 @@
#ifndef CHEST_ #ifndef CHEST_
#define CHEST_ #define CHEST_
#include <stdint.h>
#include "srslte/config.h" #include "srslte/config.h"
#define SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN 65 #define SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN 65
@ -34,7 +35,7 @@
SRSLTE_API void srslte_chest_average_pilots(cf_t *input, SRSLTE_API void srslte_chest_average_pilots(cf_t *input,
cf_t *output, cf_t *output,
cf_t *filter, float *filter,
uint32_t nof_ref, uint32_t nof_ref,
uint32_t nof_symbols, uint32_t nof_symbols,
uint32_t filter_len); uint32_t filter_len);

@ -56,7 +56,6 @@ typedef struct {
bool dmrs_signal_configured; bool dmrs_signal_configured;
cf_t *pilot_estimates; cf_t *pilot_estimates;
cf_t *pilot_estimates_average;
cf_t *pilot_recv_signal; cf_t *pilot_recv_signal;
cf_t *tmp_noise; cf_t *tmp_noise;
@ -94,8 +93,11 @@ SRSLTE_API void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q,
SRSLTE_API int srslte_chest_ul_estimate(srslte_chest_ul_t *q, SRSLTE_API int srslte_chest_ul_estimate(srslte_chest_ul_t *q,
cf_t *input, cf_t *input,
cf_t *ce[SRSLTE_MAX_PORTS], cf_t *ce,
uint32_t sf_idx); uint32_t nof_prb,
uint32_t sf_idx,
uint32_t cyclic_shift_for_dmrs,
uint32_t n_prb[2]);
SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q); SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q);

@ -36,6 +36,7 @@
#define INTERP_H #define INTERP_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "srslte/config.h" #include "srslte/config.h"
@ -87,6 +88,15 @@ SRSLTE_API void srslte_interp_linear_vector2(srslte_interp_linsrslte_vec_t *q,
cf_t *between, cf_t *between,
uint32_t M); uint32_t M);
SRSLTE_API void srslte_interp_linear_vector3(srslte_interp_linsrslte_vec_t *q,
cf_t *in0,
cf_t *in1,
cf_t *start,
cf_t *between,
uint32_t M,
bool to_right,
uint32_t len);
/* Interpolation within a vector */ /* Interpolation within a vector */
typedef struct { typedef struct {

@ -48,6 +48,7 @@
#include "srslte/common/sequence.h" #include "srslte/common/sequence.h"
#include "srslte/common/phy_common.h" #include "srslte/common/phy_common.h"
#include "srslte/ch_estimation/chest_ul.h"
#include "srslte/ch_estimation/chest_dl.h" #include "srslte/ch_estimation/chest_dl.h"
#include "srslte/ch_estimation/refsignal_dl.h" #include "srslte/ch_estimation/refsignal_dl.h"
#include "srslte/ch_estimation/refsignal_ul.h" #include "srslte/ch_estimation/refsignal_ul.h"

@ -92,6 +92,7 @@ endif(RF_FOUND)
if(VOLK_FOUND) if(VOLK_FOUND)
target_link_libraries(srslte ${VOLK_LIBRARIES}) target_link_libraries(srslte ${VOLK_LIBRARIES})
target_link_libraries(srslte_static ${VOLK_LIBRARIES})
endif(VOLK_FOUND) endif(VOLK_FOUND)
INSTALL(TARGETS srslte DESTINATION ${LIBRARY_DIR}) INSTALL(TARGETS srslte DESTINATION ${LIBRARY_DIR})

@ -72,7 +72,7 @@ void srslte_chest_set_smooth_filter3_coeff(float *smooth_filter, float w)
smooth_filter[1] = 1-2*w; smooth_filter[1] = 1-2*w;
} }
void srslte_chest_average_pilots(cf_t *input, cf_t *output, cf_t *filter, void srslte_chest_average_pilots(cf_t *input, cf_t *output, float *filter,
uint32_t nof_ref, uint32_t nof_symbols, uint32_t filter_len) uint32_t nof_ref, uint32_t nof_symbols, uint32_t filter_len)
{ {
for (int l=0;l<nof_symbols;l++) { for (int l=0;l<nof_symbols;l++) {

@ -256,6 +256,17 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint
srslte_chest_average_pilots(input, output, q->smooth_filter, nref, nsymbols, q->smooth_filter_len); srslte_chest_average_pilots(input, output, q->smooth_filter, nref, nsymbols, q->smooth_filter_len);
} }
float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) {
uint32_t l;
float rssi = 0;
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
for (l=0;l<nsymbols;l++) {
cf_t *tmp = &input[srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE];
rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE);
}
return rssi/nsymbols;
}
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) 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)
{ {
@ -322,17 +333,7 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) {
#endif #endif
} }
float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) {
uint32_t l;
float rssi = 0;
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
for (l=0;l<nsymbols;l++) {
cf_t *tmp = &input[srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE];
rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE);
}
return rssi/nsymbols;
}
float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) { float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) {
return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE; return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE;

@ -59,6 +59,8 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell)
{ {
bzero(q, sizeof(srslte_chest_ul_t)); bzero(q, sizeof(srslte_chest_ul_t));
q->cell = cell;
ret = srslte_refsignal_ul_init(&q->dmrs_signal, cell); ret = srslte_refsignal_ul_init(&q->dmrs_signal, cell);
if (ret != SRSLTE_SUCCESS) { if (ret != SRSLTE_SUCCESS) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
@ -75,12 +77,7 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell)
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF); q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * (NOF_REFS_SF+1));
if (!q->pilot_estimates_average) {
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF);
if (!q->pilot_recv_signal) { if (!q->pilot_recv_signal) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
@ -92,9 +89,8 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell)
} }
q->smooth_filter_len = 3; q->smooth_filter_len = 3;
srslte_chest_ul_set_smooth_filter3_coeff(q, 0.1); srslte_chest_ul_set_smooth_filter3_coeff(q, 0.3333);
q->cell = cell;
} }
q->dmrs_signal_configured = false; q->dmrs_signal_configured = false;
@ -110,8 +106,10 @@ clean_exit:
void srslte_chest_ul_free(srslte_chest_ul_t *q) void srslte_chest_ul_free(srslte_chest_ul_t *q)
{ {
if (q->dmrs_signal_configured) {
srslte_refsignal_dmrs_pusch_pregen_free(&q->dmrs_signal, &q->dmrs_pregen);
}
srslte_refsignal_ul_free(&q->dmrs_signal); srslte_refsignal_ul_free(&q->dmrs_signal);
if (q->tmp_noise) { if (q->tmp_noise) {
free(q->tmp_noise); free(q->tmp_noise);
} }
@ -120,9 +118,6 @@ void srslte_chest_ul_free(srslte_chest_ul_t *q)
if (q->pilot_estimates) { if (q->pilot_estimates) {
free(q->pilot_estimates); free(q->pilot_estimates);
} }
if (q->pilot_estimates_average) {
free(q->pilot_estimates_average);
}
if (q->pilot_recv_signal) { if (q->pilot_recv_signal) {
free(q->pilot_recv_signal); free(q->pilot_recv_signal);
} }
@ -134,38 +129,48 @@ void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q,
srslte_pucch_cfg_t *pucch_cfg, srslte_pucch_cfg_t *pucch_cfg,
srslte_refsignal_srs_cfg_t *srs_cfg) srslte_refsignal_srs_cfg_t *srs_cfg)
{ {
srslte_chest_ul_set_cfg(&q->dmrs_signal, pusch_cfg, pucch_cfg, srs_cfg); srslte_refsignal_ul_set_cfg(&q->dmrs_signal, pusch_cfg, pucch_cfg, srs_cfg);
srslte_refsignal_dmrs_pusch_pregen(&q->dmrs_signal, &q->dmrs_pregen); srslte_refsignal_dmrs_pusch_pregen(&q->dmrs_signal, &q->dmrs_pregen);
q->dmrs_signal_configured = true; q->dmrs_signal_configured = true;
} }
/* Uses the difference between the averaged and non-averaged pilot estimates */ /* Uses the difference between the averaged and non-averaged pilot estimates */
static float estimate_noise_pilots(srslte_chest_ul_t *q) static float estimate_noise_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs)
{ {
float power = srslte_chest_estimate_noise_pilots(q->pilot_estimates,
q->pilot_estimates_average, float power = 0;
for (int i=0;i<2;i++) {
power += srslte_chest_estimate_noise_pilots(&q->pilot_estimates[i*nrefs],
&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE],
q->tmp_noise, q->tmp_noise,
NOF_REFS_SF); nrefs);
}
power/=2;
return (1/q->smooth_filter[0])*power; if (q->smooth_filter_len == 3) {
// Calibrated for filter length 3
float w=q->smooth_filter[0];
float a=7.419*w*w+0.1117*w-0.005387;
return (power/(a*0.8));
} else {
return power;
}
} }
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *pilot_estimates, cf_t *ce) static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs)
{ {
/* interpolate the symbols with references in the freq domain */
uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, q->cell.cp); uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, q->cell.cp);
uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, q->cell.cp); uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, q->cell.cp);
uint32_t NL = SRSLTE_CP_NSYMB(q->cell.cp); uint32_t NL = 2*SRSLTE_CP_NSYMB(q->cell.cp);
/* Interpolate in the time domain between symbols */ /* Interpolate in the time domain between symbols */
srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L2), &cesymb(L1), &cesymb(L1), &cesymb(L1-1), L1, false, nrefs);
srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), NULL, &cesymb(L1+1), (L2-L1)-1, true, nrefs);
srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L2), &cesymb(L2+1), (NL-L2)-1, true, nrefs);
srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L2), &cesymb(L1), &cesymb(L1), &cesymb(L1-1), (L2-L1)-1);
srslte_interp_linear_vector( &q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L1+1), (L2-L1)-1);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L2), &cesymb(L2+1), (NL-L2)-1);
// TODO: Maybe here need to do some averaging with previous symbols?
} }
void srslte_chest_ul_set_smooth_filter(srslte_chest_ul_t *q, float *filter, uint32_t filter_len) { void srslte_chest_ul_set_smooth_filter(srslte_chest_ul_t *q, float *filter, uint32_t filter_len) {
@ -188,10 +193,12 @@ void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q, float w)
q->smooth_filter_len = 3; q->smooth_filter_len = 3;
} }
static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *output) { static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t nrefs) {
uint32_t nsymbols = 2; for (int i=0;i<2;i++) {
uint32_t nref = NOF_REFS_SYM; srslte_chest_average_pilots(&input[i*nrefs],
srslte_chest_average_pilots(input, output, q->smooth_filter, nref, nsymbols, q->smooth_filter_len); &ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE],
q->smooth_filter, nrefs, 1, q->smooth_filter_len);
}
} }
int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce,
@ -202,30 +209,37 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
int nrefs_sym = nof_prb*SRSLTE_NRE;
int nrefs_sf = nrefs_sym*2;
/* Get references from the input signal */ /* Get references from the input signal */
srslte_refsignal_dmrs_pusch_get(&q->dmrs_signal, input, nof_prb, n_prb, q->pilot_recv_signal); srslte_refsignal_dmrs_pusch_get(&q->dmrs_signal, input, nof_prb, n_prb, q->pilot_recv_signal);
/* Use the known DMRS signal to compute Least-squares estimates */ /* Use the known DMRS signal to compute Least-squares estimates */
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->dmrs_pregen.r[cyclic_shift_for_dmrs][sf_idx][nof_prb], srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->dmrs_pregen.r[cyclic_shift_for_dmrs][sf_idx][nof_prb],
q->pilot_estimates, NOF_REFS_SF); q->pilot_estimates, nrefs_sf);
if (ce != NULL) { if (ce != NULL) {
if (q->smooth_filter_len > 0) { if (q->smooth_filter_len > 0) {
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average); average_pilots(q, q->pilot_estimates, ce, nrefs_sym);
interpolate_pilots(q, q->pilot_estimates_average, ce); interpolate_pilots(q, ce, nrefs_sym);
/* If averaging, compute noise from difference between received and averaged estimates */ /* If averaging, compute noise from difference between received and averaged estimates */
if (sf_idx == 0 || sf_idx == 5) { q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym);
q->noise_estimate = estimate_noise_pilots(q);
}
} else { } else {
interpolate_pilots(q, q->pilot_estimates, ce); // Copy estimates to CE vector without averaging
for (int i=0;i<2;i++) {
memcpy(&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE],
&q->pilot_estimates[i*nrefs_sym],
nrefs_sym*sizeof(cf_t));
}
interpolate_pilots(q, ce, nrefs_sym);
q->noise_estimate = 0; q->noise_estimate = 0;
} }
} }
// Estimate received pilot power // Estimate received pilot power
q->pilot_power = srslte_vec_avg_power_cf(q->pilot_recv_signal, NOF_REFS_SF); q->pilot_power = srslte_vec_avg_power_cf(q->pilot_recv_signal, nrefs_sf);
return 0; return 0;
} }

@ -138,9 +138,9 @@ static int generate_n_prs(srslte_refsignal_ul_t * q) {
} }
q->n_prs_pusch[delta_ss][ns] = n_prs; q->n_prs_pusch[delta_ss][ns] = n_prs;
} }
srslte_sequence_free(&seq);
} }
srslte_sequence_free(&seq);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -160,9 +160,9 @@ static int generate_srslte_sequence_hopping_v(srslte_refsignal_ul_t *q) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
q->v_pusch[ns][delta_ss] = seq.c[ns]; q->v_pusch[ns][delta_ss] = seq.c[ns];
srslte_sequence_free(&seq);
} }
} }
srslte_sequence_free(&seq);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }

@ -33,22 +33,25 @@ add_test(chest_test_dl_cellid0 chest_test_dl -c 0 -r 50)
add_test(chest_test_dl_cellid1 chest_test_dl -c 1 -r 50) add_test(chest_test_dl_cellid1 chest_test_dl -c 1 -r 50)
add_test(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50) add_test(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50)
######################################################################## BuildMex(MEXNAME chest_dl SOURCES chest_test_dl_mex.c LIBRARIES srslte_static srslte_mex)
# Downlink MEX libs
########################################################################
BuildMex(MEXNAME chest SOURCES chest_test_dl_mex.c LIBRARIES srslte_static srslte_mex)
######################################################################## ########################################################################
# Uplink Channel Estimation TEST # Uplink Channel Estimation TEST
######################################################################## ########################################################################
add_executable(chest_test_ul chest_test_ul.c)
target_link_libraries(chest_test_ul srslte)
add_executable(refsignal_ul_test_all refsignal_ul_test.c) add_executable(refsignal_ul_test_all refsignal_ul_test.c)
target_link_libraries(refsignal_ul_test_all srslte) target_link_libraries(refsignal_ul_test_all srslte)
BuildMex(MEXNAME refsignal_pusch SOURCES refsignal_pusch_mex.c LIBRARIES srslte_static srslte_mex) add_test(chest_test_ul_cellid0 chest_test_ul -c 0 -r 50)
add_test(chest_test_ul_cellid1 chest_test_ul -c 1 -r 50)
add_test(chest_test_ul_cellid1 chest_test_ul -c 2 -r 50)
BuildMex(MEXNAME chest_ul SOURCES chest_test_ul_mex.c LIBRARIES srslte_static srslte_mex)
BuildMex(MEXNAME refsignal_pusch SOURCES refsignal_pusch_mex.c LIBRARIES srslte_static srslte_mex)
BuildMex(MEXNAME refsignal_srs SOURCES refsignal_srs_mex.c LIBRARIES srslte_static srslte_mex) BuildMex(MEXNAME refsignal_srs SOURCES refsignal_srs_mex.c LIBRARIES srslte_static srslte_mex)

@ -32,21 +32,14 @@
/** MEX function to be called from MATLAB to test the channel estimator /** MEX function to be called from MATLAB to test the channel estimator
*/ */
#define CELLID prhs[0] #define ENBCFG prhs[0]
#define PORTS prhs[1] #define INPUT prhs[1]
#define INPUT prhs[2] #define NOF_INPUTS 2
#define NOF_INPUTS 3
void help() void help()
{ {
mexErrMsgTxt mexErrMsgTxt
("[estChannel, avg_refs, output] = srslte_chest(cell_id, nof_ports, inputSignal)\n\n" ("[estChannel, noiseEst, eq_output] = srslte_chest_dl(enb, inputSignal, [w_coeff])\n");
" Returns a matrix of size equal to the inputSignal matrix with the channel estimates\n "
"for each resource element in inputSignal. The inputSignal matrix is the received Grid\n"
"of size nof_resource_elements x nof_ofdm_symbols.\n"
"The sf_idx is the subframe index only used if inputSignal is 1 subframe length.\n"
"Returns the averaged references and output signal after ZF/MMSE equalization\n"
);
} }
/* the gateway function */ /* the gateway function */
@ -57,95 +50,55 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_cell_t cell; srslte_cell_t cell;
srslte_chest_dl_t chest; srslte_chest_dl_t chest;
cf_t *input_signal = NULL, *output_signal[SRSLTE_MAX_LAYERS]; cf_t *input_signal = NULL, *output_signal = NULL, *tmp_x[SRSLTE_MAX_LAYERS];
cf_t *output_signal2 = NULL;
cf_t *ce[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS];
double *outr0=NULL, *outi0=NULL;
double *outr1=NULL, *outi1=NULL;
double *outr2=NULL, *outi2=NULL;
if (!mxIsDouble(CELLID) && mxGetN(CELLID) != 1 && for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
!mxIsDouble(PORTS) && mxGetN(PORTS) != 1 && tmp_x[i] = NULL;
mxGetM(CELLID) != 1) { }
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ce[i] = NULL;
}
if (nrhs < NOF_INPUTS) {
help(); help();
return; return;
} }
cell.id = (uint32_t) *((double*) mxGetPr(CELLID)); if (mexutils_read_cell(ENBCFG, &cell)) {
cell.nof_prb = mxGetM(INPUT)/SRSLTE_NRE;
cell.nof_ports = (uint32_t) *((double*) mxGetPr(PORTS));
if ((mxGetN(INPUT)%14) == 0) {
cell.cp = SRSLTE_CP_NORM;
} else if ((mxGetN(INPUT)%12)!=0) {
cell.cp = SRSLTE_CP_EXT;
} else {
mexErrMsgTxt("Invalid number of symbols\n");
help(); help();
return; return;
} }
if (srslte_chest_dl_init(&chest, cell)) { uint32_t sf_idx=0;
mexErrMsgTxt("Error initiating channel estimator\n"); if (mexutils_read_uint32_struct(ENBCFG, "NSubframe", &sf_idx)) {
help();
return; return;
} }
int nsubframes; if (srslte_chest_dl_init(&chest, cell)) {
if (cell.cp == SRSLTE_CP_NORM) { mexErrMsgTxt("Error initiating channel estimator\n");
nsubframes = mxGetN(INPUT)/14; return;
} else {
nsubframes = mxGetN(INPUT)/12;
} }
uint32_t sf_idx=0;
double *inr=(double *)mxGetPr(INPUT);
double *ini=(double *)mxGetPi(INPUT);
/** Allocate input buffers */ /** Allocate input buffers */
int nof_re = 2*SRSLTE_CP_NSYMB(cell.cp)*cell.nof_prb*SRSLTE_NRE; int nof_re = 2*SRSLTE_CP_NSYMB(cell.cp)*cell.nof_prb*SRSLTE_NRE;
for (i=0;i<SRSLTE_MAX_PORTS;i++) { for (i=0;i<SRSLTE_MAX_PORTS;i++) {
ce[i] = srslte_vec_malloc(nof_re * sizeof(cf_t)); ce[i] = srslte_vec_malloc(nof_re * sizeof(cf_t));
} }
input_signal = srslte_vec_malloc(nof_re * sizeof(cf_t)); for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
for (i=0;i<SRSLTE_MAX_PORTS;i++) { tmp_x[i] = srslte_vec_malloc(nof_re * sizeof(cf_t));
output_signal[i] = srslte_vec_malloc(nof_re * sizeof(cf_t));
} }
output_signal2 = srslte_vec_malloc(nof_re * sizeof(cf_t)); output_signal = srslte_vec_malloc(nof_re * sizeof(cf_t));
/* Create output values */ // Read input signal
if (nlhs >= 1) { int insignal_len = mexutils_read_cf(INPUT, &input_signal);
plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX); if (insignal_len < 0) {
outr0 = mxGetPr(plhs[0]); mexErrMsgTxt("Error reading input signal\n");
outi0 = mxGetPi(plhs[0]); return;
}
if (nlhs >= 2) {
plhs[1] = mxCreateDoubleMatrix(SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)*nsubframes, cell.nof_ports, mxCOMPLEX);
outr1 = mxGetPr(plhs[1]);
outi1 = mxGetPi(plhs[1]);
}
if (nlhs >= 3) {
plhs[2] = mxCreateDoubleMatrix(nof_re * nsubframes, 1, mxCOMPLEX);
outr2 = mxGetPr(plhs[2]);
outi2 = mxGetPi(plhs[2]);
}
float noise_power=0;
for (int sf=0;sf<nsubframes;sf++) {
/* Convert input to C complex type */
for (i=0;i<nof_re;i++) {
__real__ input_signal[i] = (float) *inr;
if (ini) {
__imag__ input_signal[i] = (float) *ini;
}
inr++;
ini++;
}
if (nsubframes != 1) {
sf_idx = sf%10;
} }
// Read optional value smooth filter coefficient
if (nrhs > NOF_INPUTS) { if (nrhs > NOF_INPUTS) {
float w = (float) mxGetScalar(prhs[NOF_INPUTS]); float w = (float) mxGetScalar(prhs[NOF_INPUTS]);
srslte_chest_dl_set_smooth_filter3_coeff(&chest, w); srslte_chest_dl_set_smooth_filter3_coeff(&chest, w);
@ -153,63 +106,54 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_chest_dl_set_smooth_filter(&chest, NULL, 0); srslte_chest_dl_set_smooth_filter(&chest, NULL, 0);
} }
// Perform channel estimation
if (srslte_chest_dl_estimate(&chest, input_signal, ce, sf_idx)) { if (srslte_chest_dl_estimate(&chest, input_signal, ce, sf_idx)) {
mexErrMsgTxt("Error running channel estimator\n"); mexErrMsgTxt("Error running channel estimator\n");
return; return;
} }
if (sf==0) { // Get noise power estimation
noise_power = srslte_chest_dl_get_noise_estimate(&chest); float noise_power = srslte_chest_dl_get_noise_estimate(&chest);
}
// Perform channel equalization
if (cell.nof_ports == 1) { if (cell.nof_ports == 1) {
srslte_predecoding_single(input_signal, ce[0], output_signal2, nof_re, srslte_chest_dl_get_noise_estimate(&chest)); srslte_predecoding_single(input_signal, ce[0], output_signal, nof_re, noise_power);
} else { } else {
srslte_predecoding_diversity(input_signal, ce, output_signal, cell.nof_ports, nof_re); srslte_predecoding_diversity(input_signal, ce, tmp_x, cell.nof_ports, nof_re);
srslte_layerdemap_diversity(output_signal, output_signal2, cell.nof_ports, nof_re/cell.nof_ports); srslte_layerdemap_diversity(tmp_x, output_signal, cell.nof_ports, nof_re/cell.nof_ports);
} }
/* Write output values */
if (nlhs >= 1) { if (nlhs >= 1) {
for (i=0;i<nof_re;i++) { mexutils_write_cf(ce[0], &plhs[0], mxGetM(INPUT), mxGetN(INPUT));
*outr0 = (double) crealf(ce[0][i]);
if (outi0) {
*outi0 = (double) cimagf(ce[0][i]);
}
outr0++;
outi0++;
}
} }
if (nlhs >= 2) { if (nlhs >= 2) {
for (i=0;i<SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb,0);i++) { plhs[1] = mxCreateLogicalScalar(noise_power);
*outr1 = (double) crealf(chest.pilot_estimates_average[i]);
if (outi1) {
*outi1 = (double) cimagf(chest.pilot_estimates_average[i]);
}
outr1++;
outi1++;
}
} }
if (nlhs >= 3) { if (nlhs >= 3) {
for (i=0;i<nof_re;i++) { mexutils_write_cf(output_signal, &plhs[2], mxGetM(INPUT), mxGetN(INPUT));
*outr2 = (double) crealf(output_signal2[i]); }
if (outi2) {
*outi2 = (double) cimagf(output_signal2[i]); // Free all memory
srslte_chest_dl_free(&chest);
for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
if (tmp_x[i]) {
free(tmp_x[i]);
} }
outr2++;
outi2++;
} }
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
if (ce[i]) {
free(ce[i]);
} }
} }
if (input_signal) {
if (nlhs >= 4) { free(input_signal);
plhs[3] = mxCreateDoubleScalar(noise_power);
} }
if (nlhs >= 5) { if (output_signal) {
plhs[4] = mxCreateDoubleScalar(srslte_chest_dl_get_rsrp(&chest)); free(output_signal);
} }
srslte_chest_dl_free(&chest);
return; return;
} }

@ -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;
}

@ -97,7 +97,7 @@ int main(int argc, char **argv) {
for (int delta_ss=29;delta_ss<SRSLTE_NOF_DELTA_SS;delta_ss++) { for (int delta_ss=29;delta_ss<SRSLTE_NOF_DELTA_SS;delta_ss++) {
for (int cshift=0;cshift<SRSLTE_NOF_CSHIFT;cshift++) { for (int cshift=0;cshift<SRSLTE_NOF_CSHIFT;cshift++) {
for (int h=0;h<3;h++) { for (int h=0;h<3;h++) {
for (int sf_idx=0;sf_idx<SRSLTE_NSLOTS_X_FRAME;sf_idx++) { for (int sf_idx=0;sf_idx<10;sf_idx++) {
for (int cshift_dmrs=0;cshift_dmrs<SRSLTE_NOF_CSHIFT;cshift_dmrs++) { for (int cshift_dmrs=0;cshift_dmrs<SRSLTE_NOF_CSHIFT;cshift_dmrs++) {
uint32_t nof_prb = n; uint32_t nof_prb = n;

@ -134,6 +134,9 @@ void srslte_sequence_free(srslte_sequence_t *q) {
if (q->c_float) { if (q->c_float) {
free(q->c_float); free(q->c_float);
} }
if (q->c_short) {
free(q->c_short);
}
bzero(q, sizeof(srslte_sequence_t)); bzero(q, sizeof(srslte_sequence_t));
} }

@ -128,19 +128,30 @@ void srslte_interp_linear_vector(srslte_interp_linsrslte_vec_t *q, cf_t *in0, cf
} }
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) 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)
{
srslte_interp_linear_vector3(q, in0, in1, start, between, M, true, q->vector_len);
}
void srslte_interp_linear_vector3(srslte_interp_linsrslte_vec_t *q, cf_t *in0, cf_t *in1, cf_t *start, cf_t *between, uint32_t M, bool to_right, uint32_t len)
{ {
uint32_t i; uint32_t i;
srslte_vec_sub_ccc(in1, in0, q->diff_vec, q->vector_len); srslte_vec_sub_ccc(in1, in0, q->diff_vec, len);
srslte_vec_sc_prod_cfc(q->diff_vec, (float) 1/(M+1), q->diff_vec, q->vector_len); srslte_vec_sc_prod_cfc(q->diff_vec, (float) 1/(M+1), q->diff_vec, len);
if (start) { if (start) {
srslte_vec_sum_ccc(start, q->diff_vec, between, q->vector_len); srslte_vec_sum_ccc(start, q->diff_vec, between, len);
} else { } else {
srslte_vec_sum_ccc(in0, q->diff_vec, between, q->vector_len); srslte_vec_sum_ccc(in0, q->diff_vec, between, len);
} }
for (i=0;i<M-1;i++) { for (i=0;i<M-1;i++) {
srslte_vec_sum_ccc(between, q->diff_vec, &between[q->vector_len], q->vector_len); // Operations are done to len samples but pointers are moved the full vector length
if (to_right) {
srslte_vec_sum_ccc(between, q->diff_vec, &between[q->vector_len], len);
between += q->vector_len; between += q->vector_len;
} else {
between -= q->vector_len;
srslte_vec_sum_ccc(&between[q->vector_len], q->diff_vec, between, len);
}
} }
} }

Loading…
Cancel
Save