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;
SNR_values_db=linspace(0,30,5);
Nrealizations=4;
SNR_values_db=100;%linspace(0,30,5);
Nrealizations=1;
w1=0.1;
w2=0.2;
@ -57,8 +57,10 @@ Ports = gridsize(3); % Number of transmit antenna ports
%% Allocate memory
Ntests=4;
hest=cell(1,Ntests);
tmpnoise=cell(1,Ntests);
for i=1:Ntests
hest{i}=zeros(K,140);
tmpnoise{i}=zeros(1,10);
end
hls=zeros(4,4*P*10);
MSE=zeros(Ntests,Nrealizations,length(SNR_values_db));
@ -173,27 +175,31 @@ rxGrid_nonoise = rxGrid_nonoise(:,1:140);
% True channel
h=rxGrid_nonoise./(txGrid);
%% 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}));
rxGrid_sf = rxGrid(:,(i-1)*14+1:i*14);
%% 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
[hest{2}(:,(1:14)+(i-1)*14), tmpnoise{2}(i)] = srslte_chest_dl(enb,rxGrid_sf);
%% LS-Linear + averaging with srsLTE
[hest{3}(:,(1:14)+(i-1)*14), tmpnoise{3}(i)] = srslte_chest_dl(enb,rxGrid_sf,w1);
%% LS-Linear + more averaging with srsLTE
[hest{4}(:,(1:14)+(i-1)*14), tmpnoise{4}(i)] = srslte_chest_dl(enb,rxGrid_sf,w2);
%% LS-Linear + averaging with srsLTE
[tmp, ~, ~, noiseEst(3,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid,w1);
hest{3}=reshape(tmp, size(hest{1}));
end
%% LS-Linear + more averaging with srsLTE
[tmp, ~, ~, noiseEst(4,nreal,snr_idx)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid,w2);
hest{4}=reshape(tmp, size(hest{1}));
%% Average noise estimates over all frame
for i=1:Ntests
noiseEst(i,nreal,snr_idx)=mean(tmpnoise{i});
end
%% Compute MSE
for i=1:Ntests
@ -203,7 +209,6 @@ 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];
@ -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 matlab %.2f dB\n', 10*log10(MSE(1,nreal,snr_idx)))
subplot(2,1,2)
plot(1:P,abs(W3(P/2,:)))
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_
#define CHEST_
#include <stdint.h>
#include "srslte/config.h"
#define SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN 65
@ -34,7 +35,7 @@
SRSLTE_API void srslte_chest_average_pilots(cf_t *input,
cf_t *output,
cf_t *filter,
float *filter,
uint32_t nof_ref,
uint32_t nof_symbols,
uint32_t filter_len);

@ -56,7 +56,6 @@ typedef struct {
bool dmrs_signal_configured;
cf_t *pilot_estimates;
cf_t *pilot_estimates_average;
cf_t *pilot_recv_signal;
cf_t *tmp_noise;
@ -93,9 +92,12 @@ SRSLTE_API void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q,
float w);
SRSLTE_API int srslte_chest_ul_estimate(srslte_chest_ul_t *q,
cf_t *input,
cf_t *ce[SRSLTE_MAX_PORTS],
uint32_t sf_idx);
cf_t *input,
cf_t *ce,
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);

@ -36,6 +36,7 @@
#define INTERP_H
#include <stdint.h>
#include <stdbool.h>
#include "srslte/config.h"
@ -43,7 +44,7 @@
/************* STATIC LINEAR INTERPOLATION FUNCTIONS */
SRSLTE_API cf_t srslte_interp_linear_onesample(cf_t input0,
cf_t input1);
cf_t input1);
SRSLTE_API cf_t srslte_interp_linear_onesample_cabs(cf_t input0,
cf_t input1);
@ -81,11 +82,20 @@ SRSLTE_API void srslte_interp_linear_vector(srslte_interp_linsrslte_vec_t *q,
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);
cf_t *in0,
cf_t *in1,
cf_t *start,
cf_t *between,
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 */

@ -48,6 +48,7 @@
#include "srslte/common/sequence.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/refsignal_dl.h"
#include "srslte/ch_estimation/refsignal_ul.h"

@ -92,6 +92,7 @@ endif(RF_FOUND)
if(VOLK_FOUND)
target_link_libraries(srslte ${VOLK_LIBRARIES})
target_link_libraries(srslte_static ${VOLK_LIBRARIES})
endif(VOLK_FOUND)
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;
}
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)
{
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);
}
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)
{
@ -322,17 +333,7 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) {
#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) {
return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE;

@ -58,6 +58,8 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell)
srslte_cell_isvalid(&cell))
{
bzero(q, sizeof(srslte_chest_ul_t));
q->cell = cell;
ret = srslte_refsignal_ul_init(&q->dmrs_signal, cell);
if (ret != SRSLTE_SUCCESS) {
@ -75,12 +77,7 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell)
perror("malloc");
goto clean_exit;
}
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF);
if (!q->pilot_estimates_average) {
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal = 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_recv_signal) {
perror("malloc");
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;
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;
@ -110,8 +106,10 @@ clean_exit:
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);
if (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) {
free(q->pilot_estimates);
}
if (q->pilot_estimates_average) {
free(q->pilot_estimates_average);
}
if (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_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);
q->dmrs_signal_configured = true;
}
/* 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,
q->tmp_noise,
NOF_REFS_SF);
return (1/q->smooth_filter[0])*power;
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,
nrefs);
}
power/=2;
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)]
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 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 */
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?
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);
}
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;
}
static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *output) {
uint32_t nsymbols = 2;
uint32_t nref = NOF_REFS_SYM;
srslte_chest_average_pilots(input, output, q->smooth_filter, nref, nsymbols, q->smooth_filter_len);
static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t nrefs) {
for (int i=0;i<2;i++) {
srslte_chest_average_pilots(&input[i*nrefs],
&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,
@ -202,30 +209,37 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce,
return SRSLTE_ERROR;
}
int nrefs_sym = nof_prb*SRSLTE_NRE;
int nrefs_sf = nrefs_sym*2;
/* Get references from the input 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 */
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 (q->smooth_filter_len > 0) {
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average);
interpolate_pilots(q, q->pilot_estimates_average, ce);
average_pilots(q, q->pilot_estimates, ce, nrefs_sym);
interpolate_pilots(q, ce, nrefs_sym);
/* 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);
}
q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym);
} 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;
}
}
// 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;
}

@ -138,9 +138,9 @@ static int generate_n_prs(srslte_refsignal_ul_t * q) {
}
q->n_prs_pusch[delta_ss][ns] = n_prs;
}
srslte_sequence_free(&seq);
}
srslte_sequence_free(&seq);
return SRSLTE_SUCCESS;
}
@ -160,9 +160,9 @@ static int generate_srslte_sequence_hopping_v(srslte_refsignal_ul_t *q) {
return SRSLTE_ERROR;
}
q->v_pusch[ns][delta_ss] = seq.c[ns];
srslte_sequence_free(&seq);
}
}
srslte_sequence_free(&seq);
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_cellid2 chest_test_dl -c 2 -r 50)
########################################################################
# Downlink MEX libs
########################################################################
BuildMex(MEXNAME chest SOURCES chest_test_dl_mex.c LIBRARIES srslte_static srslte_mex)
BuildMex(MEXNAME chest_dl SOURCES chest_test_dl_mex.c LIBRARIES srslte_static srslte_mex)
########################################################################
# 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)
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)

@ -32,21 +32,14 @@
/** MEX function to be called from MATLAB to test the channel estimator
*/
#define CELLID prhs[0]
#define PORTS prhs[1]
#define INPUT prhs[2]
#define NOF_INPUTS 3
#define ENBCFG prhs[0]
#define INPUT prhs[1]
#define NOF_INPUTS 2
void help()
{
mexErrMsgTxt
("[estChannel, avg_refs, output] = srslte_chest(cell_id, nof_ports, inputSignal)\n\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"
);
("[estChannel, noiseEst, eq_output] = srslte_chest_dl(enb, inputSignal, [w_coeff])\n");
}
/* the gateway function */
@ -57,158 +50,109 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_cell_t cell;
srslte_chest_dl_t chest;
cf_t *input_signal = NULL, *output_signal[SRSLTE_MAX_LAYERS];
cf_t *output_signal2 = NULL;
cf_t *input_signal = NULL, *output_signal = NULL, *tmp_x[SRSLTE_MAX_LAYERS];
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 &&
!mxIsDouble(PORTS) && mxGetN(PORTS) != 1 &&
mxGetM(CELLID) != 1) {
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
tmp_x[i] = NULL;
}
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ce[i] = NULL;
}
if (nrhs < NOF_INPUTS) {
help();
return;
}
cell.id = (uint32_t) *((double*) mxGetPr(CELLID));
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");
if (mexutils_read_cell(ENBCFG, &cell)) {
help();
return;
}
uint32_t sf_idx=0;
if (mexutils_read_uint32_struct(ENBCFG, "NSubframe", &sf_idx)) {
help();
return;
}
if (srslte_chest_dl_init(&chest, cell)) {
mexErrMsgTxt("Error initiating channel estimator\n");
return;
}
int nsubframes;
if (cell.cp == SRSLTE_CP_NORM) {
nsubframes = mxGetN(INPUT)/14;
} else {
nsubframes = mxGetN(INPUT)/12;
}
uint32_t sf_idx=0;
double *inr=(double *)mxGetPr(INPUT);
double *ini=(double *)mxGetPi(INPUT);
/** Allocate input buffers */
int nof_re = 2*SRSLTE_CP_NSYMB(cell.cp)*cell.nof_prb*SRSLTE_NRE;
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
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_PORTS;i++) {
output_signal[i] = srslte_vec_malloc(nof_re * sizeof(cf_t));
for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
tmp_x[i] = 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;
}
output_signal2 = srslte_vec_malloc(nof_re * sizeof(cf_t));
/* Create output values */
// Read optional value smooth filter coefficient
if (nrhs > NOF_INPUTS) {
float w = (float) mxGetScalar(prhs[NOF_INPUTS]);
srslte_chest_dl_set_smooth_filter3_coeff(&chest, w);
} else {
srslte_chest_dl_set_smooth_filter(&chest, NULL, 0);
}
// Perform channel estimation
if (srslte_chest_dl_estimate(&chest, input_signal, ce, sf_idx)) {
mexErrMsgTxt("Error running channel estimator\n");
return;
}
// Get noise power estimation
float noise_power = srslte_chest_dl_get_noise_estimate(&chest);
// Perform channel equalization
if (cell.nof_ports == 1) {
srslte_predecoding_single(input_signal, ce[0], output_signal, nof_re, noise_power);
} else {
srslte_predecoding_diversity(input_signal, ce, tmp_x, cell.nof_ports, nof_re);
srslte_layerdemap_diversity(tmp_x, output_signal, cell.nof_ports, nof_re/cell.nof_ports);
}
/* Write output values */
if (nlhs >= 1) {
plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX);
outr0 = mxGetPr(plhs[0]);
outi0 = mxGetPi(plhs[0]);
mexutils_write_cf(ce[0], &plhs[0], mxGetM(INPUT), mxGetN(INPUT));
}
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]);
plhs[1] = mxCreateLogicalScalar(noise_power);
}
if (nlhs >= 3) {
plhs[2] = mxCreateDoubleMatrix(nof_re * nsubframes, 1, mxCOMPLEX);
outr2 = mxGetPr(plhs[2]);
outi2 = mxGetPi(plhs[2]);
mexutils_write_cf(output_signal, &plhs[2], mxGetM(INPUT), mxGetN(INPUT));
}
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;
}
if (nrhs > NOF_INPUTS) {
float w = (float) mxGetScalar(prhs[NOF_INPUTS]);
srslte_chest_dl_set_smooth_filter3_coeff(&chest, w);
} else {
srslte_chest_dl_set_smooth_filter(&chest, NULL, 0);
}
if (srslte_chest_dl_estimate(&chest, input_signal, ce, sf_idx)) {
mexErrMsgTxt("Error running channel estimator\n");
return;
}
if (sf==0) {
noise_power = srslte_chest_dl_get_noise_estimate(&chest);
}
if (cell.nof_ports == 1) {
srslte_predecoding_single(input_signal, ce[0], output_signal2, nof_re, srslte_chest_dl_get_noise_estimate(&chest));
} else {
srslte_predecoding_diversity(input_signal, ce, output_signal, cell.nof_ports, nof_re);
srslte_layerdemap_diversity(output_signal, output_signal2, cell.nof_ports, nof_re/cell.nof_ports);
}
if (nlhs >= 1) {
for (i=0;i<nof_re;i++) {
*outr0 = (double) crealf(ce[0][i]);
if (outi0) {
*outi0 = (double) cimagf(ce[0][i]);
}
outr0++;
outi0++;
}
}
if (nlhs >= 2) {
for (i=0;i<SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb,0);i++) {
*outr1 = (double) crealf(chest.pilot_estimates_average[i]);
if (outi1) {
*outi1 = (double) cimagf(chest.pilot_estimates_average[i]);
}
outr1++;
outi1++;
}
// Free all memory
srslte_chest_dl_free(&chest);
for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
if (tmp_x[i]) {
free(tmp_x[i]);
}
if (nlhs >= 3) {
for (i=0;i<nof_re;i++) {
*outr2 = (double) crealf(output_signal2[i]);
if (outi2) {
*outi2 = (double) cimagf(output_signal2[i]);
}
outr2++;
outi2++;
}
}
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
if (ce[i]) {
free(ce[i]);
}
}
if (nlhs >= 4) {
plhs[3] = mxCreateDoubleScalar(noise_power);
if (input_signal) {
free(input_signal);
}
if (nlhs >= 5) {
plhs[4] = mxCreateDoubleScalar(srslte_chest_dl_get_rsrp(&chest));
if (output_signal) {
free(output_signal);
}
srslte_chest_dl_free(&chest);
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 cshift=0;cshift<SRSLTE_NOF_CSHIFT;cshift++) {
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++) {
uint32_t nof_prb = n;

@ -134,6 +134,9 @@ void srslte_sequence_free(srslte_sequence_t *q) {
if (q->c_float) {
free(q->c_float);
}
if (q->c_short) {
free(q->c_short);
}
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)
{
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;
srslte_vec_sub_ccc(in1, in0, q->diff_vec, q->vector_len);
srslte_vec_sc_prod_cfc(q->diff_vec, (float) 1/(M+1), 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, len);
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 {
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++) {
srslte_vec_sum_ccc(between, q->diff_vec, &between[q->vector_len], q->vector_len);
between += q->vector_len;
for (i=0;i<M-1;i++) {
// 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;
} else {
between -= q->vector_len;
srslte_vec_sum_ccc(&between[q->vector_len], q->diff_vec, between, len);
}
}
}

Loading…
Cancel
Save