Added MAC BSR. Channel estimation does averaging after interpolation

master
ismagom 10 years ago
parent 5d122ee44f
commit 486fd46234

@ -6,7 +6,7 @@ clear
plot_noise_estimation_only=false; plot_noise_estimation_only=false;
SNR_values_db=20;%linspace(0,30,8); SNR_values_db=10;%linspace(0,30,8);
Nrealizations=1 ; Nrealizations=1 ;
preEVM = zeros(length(SNR_values_db),Nrealizations); preEVM = zeros(length(SNR_values_db),Nrealizations);
@ -147,7 +147,7 @@ rxWaveform = rxWaveform(1+offset+2:end,:);
rxGrid = lteOFDMDemodulate(enb,rxWaveform); rxGrid = lteOFDMDemodulate(enb,rxWaveform);
rxGrid = rxGrid(:,1:140); rxGrid = rxGrid(:,1:140);
addpath('../../debug/srslte/lib/ch_estimation/test') addpath('../../build/srslte/lib/ch_estimation/test')
%% Channel Estimation %% Channel Estimation
[estChannel, noiseEst(snr_idx)] = lteDLChannelEstimate(enb,cec,rxGrid); [estChannel, noiseEst(snr_idx)] = lteDLChannelEstimate(enb,cec,rxGrid);
@ -156,68 +156,69 @@ snrest_srslte = zeros(10,1);
noise_srslte = zeros(10,1); noise_srslte = zeros(10,1);
rsrp = zeros(1,10); rsrp = zeros(1,10);
for i=0:9 [d, ~, out] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid);
[d, a, out, snrest_srslte(i+1), noise_srslte(i+1), rsrp(i+1)] = srslte_chest(enb.NCellID,enb.CellRefP,rxGrid(:,i*14+1:(i+1)*14),[0.1 0.8 0.1],[0.1 0.9],i); output = [output out];
output = [output out]; %RSRP = [RSRP rsrp];
%meanRSRP(snr_idx)=mean(rsrp);
%SNR_srslte(snr_idx)=mean(snrest_srslte);
%noiseEst_srslte(snr_idx)=mean(noise_srslte);
d=reshape(d, size(estChannel));
plot(1:288,real(reshape(estChannel(:,11:14),1,[])),'b-',...
1:288,real(reshape(d(:,11:14),1,[])),'r-')
% if ~plot_noise_estimation_only
%
% %% MMSE Equalization
% eqGrid_mmse = lteEqualizeMMSE(rxGrid, estChannel, noiseEst(snr_idx));
%
% eqGrid_srslte = reshape(output,size(eqGrid_mmse));
%
% % Analysis
%
% %Compute EVM across all input values EVM of pre-equalized receive signal
% preEqualisedEVM = lteEVM(txGrid,rxGrid);
% fprintf('%d-%d: Pre-EQ: %0.3f%%\n', ...
% snr_idx,nreal,preEqualisedEVM.RMS*100);
%
%
% %EVM of post-equalized receive signal
% postEqualisedEVM_mmse = lteEVM(txGrid,reshape(eqGrid_mmse,size(txGrid)));
% fprintf('%d-%d: MMSE: %0.3f%%\n', ...
% snr_idx,nreal,postEqualisedEVM_mmse.RMS*100);
%
% postEqualisedEVM_srslte = lteEVM(txGrid,reshape(eqGrid_srslte,size(txGrid)));
% fprintf('%d-%d: srslte: %0.3f%%\n', ...
% snr_idx,nreal,postEqualisedEVM_srslte.RMS*100);
%
% preEVM(snr_idx,nreal) = preEqualisedEVM.RMS;
% postEVM_mmse(snr_idx,nreal) = mean([postEqualisedEVM_mmse.RMS]);
% postEVM_srslte(snr_idx,nreal) = mean([postEqualisedEVM_srslte.RMS]);
% end
end end
RSRP = [RSRP rsrp];
meanRSRP(snr_idx)=mean(rsrp);
SNR_srslte(snr_idx)=mean(snrest_srslte);
noiseEst_srslte(snr_idx)=mean(noise_srslte);
if ~plot_noise_estimation_only
%% MMSE Equalization
eqGrid_mmse = lteEqualizeMMSE(rxGrid, estChannel, noiseEst(snr_idx));
eqGrid_srslte = reshape(output,size(eqGrid_mmse));
% Analysis
%Compute EVM across all input values EVM of pre-equalized receive signal
preEqualisedEVM = lteEVM(txGrid,rxGrid);
fprintf('%d-%d: Pre-EQ: %0.3f%%\n', ...
snr_idx,nreal,preEqualisedEVM.RMS*100);
%EVM of post-equalized receive signal
postEqualisedEVM_mmse = lteEVM(txGrid,reshape(eqGrid_mmse,size(txGrid)));
fprintf('%d-%d: MMSE: %0.3f%%\n', ...
snr_idx,nreal,postEqualisedEVM_mmse.RMS*100);
postEqualisedEVM_srslte = lteEVM(txGrid,reshape(eqGrid_srslte,size(txGrid)));
fprintf('%d-%d: srslte: %0.3f%%\n', ...
snr_idx,nreal,postEqualisedEVM_srslte.RMS*100);
preEVM(snr_idx,nreal) = preEqualisedEVM.RMS;
postEVM_mmse(snr_idx,nreal) = mean([postEqualisedEVM_mmse.RMS]);
postEVM_srslte(snr_idx,nreal) = mean([postEqualisedEVM_srslte.RMS]);
end
end
end
% subplot(1,2,1)
if ~plot_noise_estimation_only
plot(SNR_values_db, mean(preEVM,2), ...
SNR_values_db, mean(postEVM_mmse,2), ...
SNR_values_db, mean(postEVM_srslte,2))
legend('No Eq','MMSE-lin','MMSE-srslte')
grid on
end
% subplot(1,2,2)
if plot_noise_estimation_only
SNR_matlab = 1./(noiseEst*sqrt(2.0)*enb.CellRefP);
subplot(1,3,1)
plot(SNR_values_db, SNR_values_db, SNR_values_db, 10*log10(SNR_srslte),SNR_values_db, 10*log10(SNR_matlab))
legend('Theory','srsLTE','Matlab')
subplot(1,3,2)
plot(SNR_values_db, 10*log10(noiseTx), SNR_values_db, 10*log10(noiseEst_srslte),SNR_values_db, 10*log10(noiseEst))
legend('Theory','srsLTE','Matlab')
subplot(1,3,3)
plot(1:10*length(SNR_values_db),RSRP,10*(1:length(SNR_values_db)),meanRSRP)
end end
%
% % subplot(1,2,1)
%
% if ~plot_noise_estimation_only
% plot(SNR_values_db, mean(preEVM,2), ...
% SNR_values_db, mean(postEVM_mmse,2), ...
% SNR_values_db, mean(postEVM_srslte,2))
% legend('No Eq','MMSE-lin','MMSE-srslte')
% grid on
% end
%
% % subplot(1,2,2)
% if plot_noise_estimation_only
% SNR_matlab = 1./(noiseEst*sqrt(2.0)*enb.CellRefP);
%
% subplot(1,3,1)
% plot(SNR_values_db, SNR_values_db, SNR_values_db, 10*log10(SNR_srslte),SNR_values_db, 10*log10(SNR_matlab))
% legend('Theory','srsLTE','Matlab')
%
% subplot(1,3,2)
% plot(SNR_values_db, 10*log10(noiseTx), SNR_values_db, 10*log10(noiseEst_srslte),SNR_values_db, 10*log10(noiseEst))
% legend('Theory','srsLTE','Matlab')
%
% subplot(1,3,3)
% plot(1:10*length(SNR_values_db),RSRP,10*(1:length(SNR_values_db)),meanRSRP)
% end

@ -40,12 +40,13 @@ namespace ue {
public: public:
params_db(uint32_t nof_params_) { params_db(uint32_t nof_params_) {
nof_params = nof_params_; nof_params = nof_params_;
db = (int64_t*) calloc(sizeof(int64_t), nof_params); db = new int64_t[nof_params];
for (int i=0;i<nof_params;i++) {
db[i] = 0;
}
} }
~params_db() { ~params_db() {
if (db) { delete db;
free(db);
}
} }
void set_param(uint32_t param_idx, int64_t value) { void set_param(uint32_t param_idx, int64_t value) {
if (param_idx < nof_params) { if (param_idx < nof_params) {

@ -76,8 +76,7 @@ public:
int recv_dtch0_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes); // SRB0 int recv_dtch0_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes); // SRB0
int recv_dcch0_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes); // DRB0 int recv_dcch0_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes); // DRB0
void set_dcch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void set_dtch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD);
void set_param(mac_params::mac_param_t param, int64_t value); void set_param(mac_params::mac_param_t param, int64_t value);
@ -90,6 +89,8 @@ public:
HARQ_RTT = 0, HARQ_RTT = 0,
TIME_ALIGNMENT, TIME_ALIGNMENT,
CONTENTION_TIMER, CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
NOF_MAC_TIMERS NOF_MAC_TIMERS
} mac_timers_t; } mac_timers_t;

@ -83,6 +83,9 @@ namespace ue {
SR_PUCCH_CONFIGURED, SR_PUCCH_CONFIGURED,
SR_TRANS_MAX, SR_TRANS_MAX,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
HARQ_MAXTX, HARQ_MAXTX,
HARQ_MAXMSG3TX, HARQ_MAXMSG3TX,

@ -32,6 +32,7 @@
#include "srsapps/ue/mac/mac_io.h" #include "srsapps/ue/mac/mac_io.h"
#include "srsapps/ue/mac/mac_params.h" #include "srsapps/ue/mac/mac_params.h"
#include "srsapps/ue/mac/pdu.h" #include "srsapps/ue/mac/pdu.h"
#include "srsapps/ue/mac/proc_bsr.h"
#ifndef MUX_H #ifndef MUX_H
#define MUX_H #define MUX_H
@ -46,10 +47,11 @@ class mux
public: public:
mux(); mux();
void reset(); void reset();
void init(log *log_h, mac_io *mac_io_h); void init(log *log_h, mac_io *mac_io_h, bsr_proc *bsr_procedure);
bool is_pending_ccch_sdu(); bool is_pending_ccch_sdu();
bool is_pending_any_sdu(); bool is_pending_any_sdu();
bool is_pending_sdu(uint32_t lcid);
uint8_t* pdu_pop(uint32_t pdu_sz); uint8_t* pdu_pop(uint32_t pdu_sz);
bool pdu_move_to_msg3(uint32_t pdu_sz); bool pdu_move_to_msg3(uint32_t pdu_sz);
@ -60,14 +62,14 @@ public:
void msg3_transmitted(); void msg3_transmitted();
bool msg3_is_transmitted(); bool msg3_is_transmitted();
void append_crnti_ce_next_tx(uint16_t crnti); void append_crnti_ce_next_tx(uint16_t crnti);
void set_priority(uint32_t lch_id, uint32_t priority, int PBR_x_tti, uint32_t BSD); void set_priority(uint32_t lcid, uint32_t priority, int PBR_x_tti, uint32_t BSD);
private: private:
bool assemble_pdu(uint32_t pdu_sz); bool assemble_pdu(uint32_t pdu_sz);
bool allocate_sdu(uint32_t lcid, sch_pdu *pdu, uint32_t *sdu_sz);
bool allocate_sdu(uint32_t lcid, sch_pdu *pdu); bool allocate_sdu(uint32_t lcid, sch_pdu *pdu);
bool allocate_sdu(uint32_t lcid, sch_pdu *pdu, uint32_t *sdu_sz);
int64_t Bj[mac_io::NOF_UL_LCH]; int64_t Bj[mac_io::NOF_UL_LCH];
int PBR[mac_io::NOF_UL_LCH]; // -1 sets to infinity int PBR[mac_io::NOF_UL_LCH]; // -1 sets to infinity
@ -82,6 +84,7 @@ private:
log *log_h; log *log_h;
mac_io *mac_io_h; mac_io *mac_io_h;
bsr_proc *bsr_procedure;
uint16_t pending_crnti_ce; uint16_t pending_crnti_ce;
/* Msg3 Buffer */ /* Msg3 Buffer */

@ -197,6 +197,7 @@ public:
void write_payload(uint8_t **ptr); void write_payload(uint8_t **ptr);
bool set_sdu(uint32_t lcid, uint8_t *ptr, uint32_t nof_bytes); bool set_sdu(uint32_t lcid, uint8_t *ptr, uint32_t nof_bytes);
bool set_c_rnti(uint16_t crnti); bool set_c_rnti(uint16_t crnti);
bool set_bsr(uint32_t buff_size[4], sch_subh::cetype format);
bool set_con_res_id(uint64_t con_res_id); bool set_con_res_id(uint64_t con_res_id);
bool set_ta_cmd(uint8_t ta_cmd); bool set_ta_cmd(uint8_t ta_cmd);
bool set_phd(uint8_t phd); bool set_phd(uint8_t phd);
@ -211,8 +212,9 @@ private:
uint32_t nof_bytes; uint32_t nof_bytes;
uint8_t* sdu_payload_ptr; uint8_t* sdu_payload_ptr;
bool F_bit; bool F_bit;
uint8_t ce_payload[MAX_CE_PAYLOAD_LEN]; uint8_t ce_payload[MAX_CE_PAYLOAD_LEN*8];
uint32_t sizeof_ce(uint32_t lcid, bool is_ul); uint32_t sizeof_ce(uint32_t lcid, bool is_ul);
uint8_t buff_size_table(uint32_t buffer_size);
}; };
class sch_pdu : public pdu<sch_subh> class sch_pdu : public pdu<sch_subh>
@ -226,6 +228,7 @@ public:
bool has_space_ce(uint32_t nbytes); bool has_space_ce(uint32_t nbytes);
bool has_space_sdu(uint32_t nbytes); bool has_space_sdu(uint32_t nbytes);
uint32_t size(); uint32_t size();
uint32_t rem_size();
static uint32_t size_plus_header_sdu(uint32_t nbytes); static uint32_t size_plus_header_sdu(uint32_t nbytes);
bool update_space_ce(uint32_t nbytes); bool update_space_ce(uint32_t nbytes);
bool update_space_sdu(uint32_t nbytes); bool update_space_sdu(uint32_t nbytes);

@ -29,8 +29,11 @@
#include <stdint.h> #include <stdint.h>
#include "srsapps/common/log.h"
#include "srsapps/ue/mac/proc.h" #include "srsapps/ue/mac/proc.h"
#include "srsapps/ue/mac/mux.h" #include "srsapps/ue/mac/mac_params.h"
#include "srsapps/ue/mac/mac_io.h"
#include "srsapps/common/timers.h"
#ifndef PROCBSR_H #ifndef PROCBSR_H
#define PROCBSR_H #define PROCBSR_H
@ -40,20 +43,52 @@
namespace srslte { namespace srslte {
namespace ue { namespace ue {
class bsr_proc : public proc class bsr_proc : public proc, timer_callback
{ {
public: public:
bsr_proc(); bsr_proc();
void init(log *log_h, mac_params *params_db, mux *mux_unit_); void init(log *log_h, timers *timers_db, mac_params *params_db, mac_io *mac_io_h);
void step(uint32_t tti); void step(uint32_t tti);
void reset(); void reset();
void start(); void setup_lcg(uint32_t lcid, uint32_t new_lcg);
void set_priority(uint32_t lcid, uint32_t priority);
void timer_expired(uint32_t timer_id);
typedef enum {
LONG_BSR,
SHORT_BSR,
TRUNC_BSR
} bsr_format_t;
typedef struct {
bsr_format_t format;
uint32_t buff_size[4];
} bsr_t;
bool need_to_send_bsr_on_ul_grant(uint32_t nof_grant_bytes, uint32_t nof_padding_bytes, bsr_t *bsr);
bool need_to_send_sr();
private: private:
bool is_pending_sr; bool is_pending_sr;
mac_params *params_db; mac_params *params_db;
mux *mux_unit; mac_io *mac_io_h;
timers *timers_db;
log *log_h; log *log_h;
bool initiated; bool initiated;
const static int MAX_LCID = 20;
uint32_t lcg[MAX_LCID];
uint32_t priorities[MAX_LCID];
uint32_t find_max_priority_lcid();
enum {NONE, REGULAR, PADDING, PERIODIC} triggered_bsr_type;
bool timer_periodic;
bool timer_retx;
bsr_t pending_bsr;
bool sr_is_sent;
bool check_all_channels();
bool check_highest_channel();
void get_pending_bsr_format(uint32_t nof_padding_bytes);
}; };
} }

@ -47,7 +47,8 @@ bool mac::init(phy *phy_h_, tti_sync* ttisync_, log* log_h_)
tti = 0; tti = 0;
is_synchronized = false; is_synchronized = false;
mux_unit.init(log_h, &mac_io_lch); bsr_procedure.init(log_h, &timers_db, &params_db, &mac_io_lch);
mux_unit.init(log_h, &mac_io_lch, &bsr_procedure);
demux_unit.init(phy_h, log_h, &mac_io_lch, &timers_db); demux_unit.init(phy_h, log_h, &mac_io_lch, &timers_db);
ra_procedure.init(&params_db, phy_h, log_h, &timers_db, &mux_unit, &demux_unit); ra_procedure.init(&params_db, phy_h, log_h, &timers_db, &mux_unit, &demux_unit);
sr_procedure.init(log_h, &params_db, phy_h); sr_procedure.init(log_h, &params_db, phy_h);
@ -173,17 +174,23 @@ void mac::main_radio_loop() {
log_h->step(tti); log_h->step(tti);
// Step all procedures // Step all procedures
ra_procedure.step(tti); bsr_procedure.step(tti);
//sr_procedure.step(tti);
//bsr_procedure.step(tti); // Check if BSR procedure need to start SR
//phr_procedure.step(tti); if (bsr_procedure.need_to_send_sr()) {
sr_procedure.start();
}
sr_procedure.step(tti);
// Check SR if we need to start RA // Check SR if we need to start RA
/*
if (sr_procedure.need_random_access()) { if (sr_procedure.need_random_access()) {
ra_procedure.start_mac_order(); ra_procedure.start_mac_order();
} }
*/
ra_procedure.step(tti);
//phr_procedure.step(tti);
// Receive PCH, if requested // Receive PCH, if requested
receive_pch(tti); receive_pch(tti);
@ -216,13 +223,7 @@ void mac::main_radio_loop() {
Info("Starting RA procedure by RLC order\n"); Info("Starting RA procedure by RLC order\n");
ra_procedure.start_rlc_order(); ra_procedure.start_rlc_order();
} }
} /*else if (mux_unit.is_pending_any_sdu()) { }
// Sart SR if no PUSCH resources available for TTI+4
if (!ul_resources_available) {
sr_procedure.start();
Info("Starting Scheduling Request procedure\n");
}
}*/
} }
} }
} }
@ -511,13 +512,11 @@ void mac::set_param(mac_params::mac_param_t param, int64_t value)
params_db.set_param((uint32_t) param, value); params_db.set_param((uint32_t) param, value);
} }
void mac::set_dcch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD) void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD)
{
mux_unit.set_priority(mac_io::MAC_LCH_DCCH0_UL - mac_io::MAC_LCH_CCCH_UL, priority, PBR_x_tti, BSD);
}
void mac::set_dtch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD)
{ {
mux_unit.set_priority(mac_io::MAC_LCH_DTCH0_UL - mac_io::MAC_LCH_CCCH_UL, priority, PBR_x_tti, BSD); mux_unit.set_priority(mac_io::MAC_LCH_CCCH_UL+lcid, priority, PBR_x_tti, BSD);
bsr_procedure.setup_lcg(lcid, lcg);
bsr_procedure.set_priority(lcid, priority);
} }

@ -52,10 +52,11 @@ mux::mux() : pdu_msg(20)
} }
} }
void mux::init(log *log_h_, mac_io *mac_io_h_) void mux::init(log *log_h_, mac_io *mac_io_h_, bsr_proc *bsr_procedure_)
{ {
log_h = log_h_; log_h = log_h_;
mac_io_h = mac_io_h_; mac_io_h = mac_io_h_;
bsr_procedure = bsr_procedure_;
} }
void mux::reset() void mux::reset()
@ -65,6 +66,11 @@ void mux::reset()
} }
} }
bool mux::is_pending_ccch_sdu()
{
return is_pending_sdu(0);
}
bool mux::is_pending_any_sdu() bool mux::is_pending_any_sdu()
{ {
for (int i=0;i<mac_io::NOF_UL_LCH;i++) { for (int i=0;i<mac_io::NOF_UL_LCH;i++) {
@ -75,9 +81,11 @@ bool mux::is_pending_any_sdu()
return false; return false;
} }
bool mux::is_pending_ccch_sdu() bool mux::is_pending_sdu(uint32_t lch_id) {
{ lch_id += (uint32_t) mac_io::MAC_LCH_CCCH_UL;
return !mac_io_h->get(mac_io::MAC_LCH_CCCH_UL)->isempty(); if (lch_id < mac_io::MAC_NOF_QUEUES) {
return !mac_io_h->get(lch_id)->isempty();
}
} }
void mux::set_priority(uint32_t lch_id, uint32_t set_priority, int set_PBR, uint32_t set_BSD) void mux::set_priority(uint32_t lch_id, uint32_t set_priority, int set_PBR, uint32_t set_BSD)
@ -159,6 +167,18 @@ void mux::append_crnti_ce_next_tx(uint16_t crnti) {
pending_crnti_ce = crnti; pending_crnti_ce = crnti;
} }
sch_subh::cetype bsr_format_convert(bsr_proc::bsr_format_t format) {
switch(format) {
case bsr_proc::LONG_BSR:
return sch_subh::LONG_BSR;
case bsr_proc::SHORT_BSR:
return sch_subh::SHORT_BSR;
case bsr_proc::TRUNC_BSR:
return sch_subh::TRUNC_BSR;
}
}
bool mux::assemble_pdu(uint32_t pdu_sz_nbits) { bool mux::assemble_pdu(uint32_t pdu_sz_nbits) {
uint8_t *buff = (uint8_t*) pdu_buff.request(); uint8_t *buff = (uint8_t*) pdu_buff.request();
@ -203,8 +223,15 @@ bool mux::assemble_pdu(uint32_t pdu_sz_nbits) {
} }
pending_crnti_ce = 0; pending_crnti_ce = 0;
bsr_proc::bsr_t bsr;
bool send_bsr_normal = bsr_procedure->need_to_send_bsr_on_ul_grant(pdu_sz_nbits/8, 0, &bsr);
// MAC control element for BSR, with exception of BSR included for padding; // MAC control element for BSR, with exception of BSR included for padding;
// TODO if (send_bsr_normal) {
pdu_msg.next();
pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format));
}
// MAC control element for PHR // MAC control element for PHR
// TODO // TODO
@ -226,7 +253,11 @@ bool mux::assemble_pdu(uint32_t pdu_sz_nbits) {
} }
// MAC control element for BSR included for padding. // MAC control element for BSR included for padding.
// TODO bool send_bsr_padding = bsr_procedure->need_to_send_bsr_on_ul_grant(pdu_sz_nbits/8, pdu_msg.rem_size(), &bsr);
if (send_bsr_padding) {
pdu_msg.next();
pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format));
}
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
@ -249,12 +280,10 @@ bool mux::assemble_pdu(uint32_t pdu_sz_nbits) {
return true; return true;
} }
bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg) bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg)
{ {
return allocate_sdu(lcid, pdu_msg, NULL); return allocate_sdu(lcid, pdu_msg, NULL);
} }
bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg, uint32_t *sdu_sz) bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg, uint32_t *sdu_sz)
{ {
@ -263,6 +292,9 @@ bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg, uint32_t *sdu_sz)
uint8_t *buff_ptr = (uint8_t*) mac_io_h->get(mac_io::MAC_LCH_CCCH_UL + lcid)->pop(&buff_len, nof_tx_pkts[lcid]); uint8_t *buff_ptr = (uint8_t*) mac_io_h->get(mac_io::MAC_LCH_CCCH_UL + lcid)->pop(&buff_len, nof_tx_pkts[lcid]);
if (buff_ptr) { // there is pending SDU to allocate if (buff_ptr) { // there is pending SDU to allocate
if (sdu_sz) {
*sdu_sz = buff_len;
}
if (pdu_msg->new_subh()) { // there is space for a new subheader if (pdu_msg->new_subh()) { // there is space for a new subheader
pdu_msg->next(); pdu_msg->next();
if (pdu_msg->get()->set_sdu(lcid, buff_ptr, buff_len/8)) { // new SDU could be added if (pdu_msg->get()->set_sdu(lcid, buff_ptr, buff_len/8)) { // new SDU could be added

@ -132,6 +132,9 @@ bool sch_pdu::write_packet(uint8_t* ptr)
} }
uint32_t sch_pdu::rem_size() {
return rem_len;
}
uint32_t sch_pdu::size() uint32_t sch_pdu::size()
{ {
@ -175,8 +178,6 @@ bool sch_pdu::update_space_sdu(uint32_t nbytes)
} }
} }
void sch_subh::init() void sch_subh::init()
{ {
lcid = 0; lcid = 0;
@ -242,19 +243,33 @@ bool sch_subh::is_sdu()
} }
uint16_t sch_subh::get_c_rnti() uint16_t sch_subh::get_c_rnti()
{ {
return *((uint16_t*) ce_payload); uint8_t *ptr = ce_payload;
uint16_t ret = (uint16_t) srslte_bit_unpack(&ptr, 16);
return ret;
} }
uint64_t sch_subh::get_con_res_id() uint64_t sch_subh::get_con_res_id()
{ {
return *((uint64_t*) ce_payload); uint8_t *ptr = ce_payload;
uint64_t ret = (uint64_t) srslte_bit_unpack_l(&ptr, 48);
return ret;
} }
uint8_t sch_subh::get_phd() uint8_t sch_subh::get_phd()
{ {
return *((uint8_t*) ce_payload); uint8_t *ptr = ce_payload;
ptr += 2;
uint8_t ret = (uint8_t) srslte_bit_unpack(&ptr, 6);
return ret;
}
uint8_t sch_subh::get_ta_cmd()
{
uint8_t *ptr = ce_payload;
ptr += 2;
uint8_t ret = (uint8_t) srslte_bit_unpack(&ptr, 6);
return ret;
} }
uint32_t sch_subh::get_sdu_lcid() uint32_t sch_subh::get_sdu_lcid()
{ {
return *((uint32_t*) ce_payload); return lcid;
} }
uint32_t sch_subh::get_sdu_nbytes() uint32_t sch_subh::get_sdu_nbytes()
{ {
@ -264,19 +279,46 @@ uint8_t* sch_subh::get_sdu_ptr()
{ {
return sdu_payload_ptr; return sdu_payload_ptr;
} }
uint8_t sch_subh::get_ta_cmd()
{
return *((uint8_t*) ce_payload);
}
void sch_subh::set_padding() void sch_subh::set_padding()
{ {
lcid = PADDING; lcid = PADDING;
} }
bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format)
{
uint32_t nonzero_lcg=0;
for (int i=0;i<4;i++) {
if (buff_size[i]) {
nonzero_lcg=i;
}
}
uint32_t ce_size = format==LONG_BSR?3:1;
if (((sch_pdu*)parent)->has_space_ce(ce_size)) {
uint8_t *ptr = ce_payload;
if (format==LONG_BSR) {
for (int i=0;i<4;i++) {
srslte_bit_pack(buff_size_table(buff_size[i]), &ptr, 6);
}
} else {
srslte_bit_pack(nonzero_lcg, &ptr, 2);
srslte_bit_pack(buff_size_table(buff_size[nonzero_lcg]), &ptr, 6);
}
lcid = format;
((sch_pdu*)parent)->update_space_ce(ce_size);
return true;
} else {
return false;
}
}
bool sch_subh::set_c_rnti(uint16_t crnti) bool sch_subh::set_c_rnti(uint16_t crnti)
{ {
if (((sch_pdu*)parent)->has_space_ce(2)) { if (((sch_pdu*)parent)->has_space_ce(2)) {
*((uint16_t*) ce_payload) = crnti; *((uint16_t*) ce_payload) = crnti;
lcid = C_RNTI; lcid = C_RNTI;
uint8_t *ptr = ce_payload;
srslte_bit_pack(crnti, &ptr, 16);
((sch_pdu*)parent)->update_space_ce(2); ((sch_pdu*)parent)->update_space_ce(2);
return true; return true;
} else { } else {
@ -286,7 +328,8 @@ bool sch_subh::set_c_rnti(uint16_t crnti)
bool sch_subh::set_con_res_id(uint64_t con_res_id) bool sch_subh::set_con_res_id(uint64_t con_res_id)
{ {
if (((sch_pdu*)parent)->has_space_ce(6)) { if (((sch_pdu*)parent)->has_space_ce(6)) {
*((uint64_t*) ce_payload) = con_res_id; uint8_t *ptr = ce_payload;
srslte_bit_pack_l(con_res_id, &ptr, 48);
lcid = CON_RES_ID; lcid = CON_RES_ID;
((sch_pdu*)parent)->update_space_ce(6); ((sch_pdu*)parent)->update_space_ce(6);
return true; return true;
@ -297,7 +340,9 @@ bool sch_subh::set_con_res_id(uint64_t con_res_id)
bool sch_subh::set_phd(uint8_t phd) bool sch_subh::set_phd(uint8_t phd)
{ {
if (((sch_pdu*)parent)->has_space_ce(1)) { if (((sch_pdu*)parent)->has_space_ce(1)) {
*((uint8_t*) ce_payload) = phd; uint8_t *ptr = ce_payload;
srslte_bit_pack(0, &ptr, 2);
srslte_bit_pack(phd, &ptr, 6);
lcid = PHD_REPORT; lcid = PHD_REPORT;
((sch_pdu*)parent)->update_space_ce(1); ((sch_pdu*)parent)->update_space_ce(1);
return true; return true;
@ -320,7 +365,9 @@ bool sch_subh::set_sdu(uint32_t lcid_, uint8_t* ptr, uint32_t nof_bytes_)
bool sch_subh::set_ta_cmd(uint8_t ta_cmd) bool sch_subh::set_ta_cmd(uint8_t ta_cmd)
{ {
if (((sch_pdu*)parent)->has_space_ce(1)) { if (((sch_pdu*)parent)->has_space_ce(1)) {
*((uint8_t*) ce_payload) = ta_cmd; uint8_t *ptr = ce_payload;
srslte_bit_pack(0, &ptr, 2);
srslte_bit_pack(ta_cmd, &ptr, 6);
lcid = TA_CMD; lcid = TA_CMD;
((sch_pdu*)parent)->update_space_ce(1); ((sch_pdu*)parent)->update_space_ce(1);
return true; return true;
@ -351,13 +398,13 @@ void sch_subh::write_subheader(uint8_t** ptr, bool is_last)
} }
void sch_subh::write_payload(uint8_t** ptr) void sch_subh::write_payload(uint8_t** ptr)
{ {
uint8_t *src;
if (is_sdu()) { if (is_sdu()) {
memcpy(*ptr, sdu_payload_ptr, nof_bytes*8*sizeof(uint8_t)); src = sdu_payload_ptr;
} else { } else {
for (int i=0;i<nof_bytes;i++) { src = ce_payload;
srslte_bit_pack(ce_payload[nof_bytes-i-1], ptr, 8);
}
} }
memcpy(*ptr, src, nof_bytes*8*sizeof(uint8_t));
*ptr += nof_bytes*8; *ptr += nof_bytes*8;
} }
bool sch_subh::read_subheader(uint8_t** ptr) bool sch_subh::read_subheader(uint8_t** ptr)
@ -383,12 +430,10 @@ void sch_subh::read_payload(uint8_t** ptr)
{ {
if (is_sdu()) { if (is_sdu()) {
sdu_payload_ptr = *ptr; sdu_payload_ptr = *ptr;
*ptr += nof_bytes*8;
} else { } else {
for (int i=0;i<nof_bytes;i++) { memcpy(ce_payload, *ptr, 8*nof_bytes*sizeof(uint8_t));
ce_payload[nof_bytes-i-1] = srslte_bit_unpack(ptr, 8);
}
} }
*ptr += nof_bytes*8;
} }
@ -539,6 +584,26 @@ bool rar_subh::read_subheader(uint8_t** ptr)
} }
// Table 6.1.3.1-1 Buffer size levels for BSR
uint32_t btable[61] = {
10, 12, 14, 17, 19, 22, 26, 31, 36, 42, 49, 57, 67, 78, 91, 107, 125, 146, 171, 200, 234, 274, 321, 376, 440, 515, 603, 706, 826, 967, 1132,
1326, 1552, 1817, 2127, 2490, 2915, 3413, 3995, 4667, 5476, 6411, 7505, 8787, 10287, 12043, 14099, 16507, 19325, 22624, 26487, 31009, 36304,
42502, 49759, 58255, 68201, 79846, 93479, 109439, 128125};
uint8_t sch_subh::buff_size_table(uint32_t buffer_size) {
if (buffer_size == 0) {
return 0;
} else if (buffer_size > 150000) {
return 63;
} else {
for (int i=0;i<61;i++) {
if (buffer_size > btable[i]) {
return 1+i;
}
}
return 62;
}
}
} }

@ -27,6 +27,8 @@
#include "srsapps/ue/mac/proc_bsr.h" #include "srsapps/ue/mac/proc_bsr.h"
#include "srsapps/ue/mac/mac_params.h" #include "srsapps/ue/mac/mac_params.h"
#include "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/mux.h"
namespace srslte { namespace srslte {
namespace ue { namespace ue {
@ -34,31 +36,245 @@ namespace srslte {
bsr_proc::bsr_proc() bsr_proc::bsr_proc()
{ {
initiated = false; initiated = false;
timer_periodic = false;
timer_retx = false;
for (int i=0;i<MAX_LCID;i++) {
lcg[i] = 0;
priorities[i] = 0;
}
} }
void bsr_proc::init(log* log_h_, mac_params* params_db_, mux *mux_unit_) void bsr_proc::init(log* log_h_, timers *timers_db_, mac_params* params_db_, mac_io *mac_io_h_)
{ {
log_h = log_h; log_h = log_h;
params_db = params_db_; params_db = params_db_;
mux_unit = mux_unit_; mac_io_h = mac_io_h_;
timers_db = timers_db_;
initiated = true; initiated = true;
} }
void bsr_proc::reset() void bsr_proc::reset()
{ {
triggered_bsr_type = NONE;
}
/* Process Periodic BSR */
void bsr_proc::timer_expired(uint32_t timer_id) {
switch(timer_id) {
case mac::BSR_TIMER_PERIODIC:
if (triggered_bsr_type == NONE) {
// Check condition 4 in Sec 5.4.5
if (check_all_channels()) {
triggered_bsr_type = PERIODIC;
}
}
break;
case mac::BSR_TIMER_RETX:
// Check condition 3 in Sec 5.4.5
if (check_all_channels()) {
triggered_bsr_type = REGULAR;
sr_is_sent = false; // Enable reTx of SR
}
break;
}
} }
void bsr_proc::start() /* Checks condition 1 for Regular BSR reporting */
{ bool bsr_proc::check_highest_channel() {
uint32_t lcg_with_data = 0;
uint32_t pending_data = 0;
uint32_t min_priority_group[4]={99, 99, 99, 99};
bool trigger_bsr = true;
// Check if data arrived for a LCG
for (uint32_t group=0;group<4;group++) {
for (int i=0;i<mac_io::NOF_UL_LCH;i++) {
if (lcg[group] == i) {
if (priorities[i] < min_priority_group[group]) {
min_priority_group[group] = priorities[i];
}
pending_data = mac_io_h->get(i)->pending_data();
if (pending_data > 0) {
lcg_with_data = group;
}
}
}
}
if (pending_data) {
// If no data is available belonging to any of the logical channels belonging to any other LCG
for (uint32_t group=0;group<4 && trigger_bsr;group++) {
if (group != lcg_with_data) {
for (int i=0;i<mac_io::NOF_UL_LCH && trigger_bsr;i++) {
if (lcg[group] == i) {
if (mac_io_h->get(i)->pending_data() && priorities[i] > min_priority_group[group]) {
trigger_bsr=false;
}
}
}
}
}
}
return trigger_bsr;
}
bool bsr_proc::check_all_channels() {
bool ret = false;
bzero(&pending_bsr, sizeof(bsr_t));
for (int i=0;i<mac_io_h->NOF_UL_LCH;i++) {
uint32_t n = mac_io_h->get(i)->pending_data();
pending_bsr.buff_size[lcg[i]] += n;
if (n > 0) {
ret = true;
}
}
return ret;
} }
void bsr_proc::get_pending_bsr_format(uint32_t nof_padding_bytes) {
uint32_t nof_lcg=0;
for (int i=0;i<4;i++) {
if (pending_bsr.buff_size[i] > 0) {
nof_lcg++;
}
}
if (triggered_bsr_type == PADDING) {
if (nof_padding_bytes < 4) {
// If space only for short
if (nof_lcg > 1) {
pending_bsr.format = TRUNC_BSR;
uint32_t max_prio_ch = find_max_priority_lcid();
for (int i=0;i<4;i++) {
if (lcg[max_prio_ch] != i) {
pending_bsr.buff_size[i] = 0;
}
}
} else {
pending_bsr.format = SHORT_BSR;
}
} else {
// If space for long BSR
pending_bsr.format = LONG_BSR;
}
} else {
pending_bsr.format = SHORT_BSR;
if (nof_lcg > 1) {
pending_bsr.format = LONG_BSR;
}
}
}
// Checks if Regular BSR must be assembled, as defined in 5.4.5
// Padding BSR is assembled when called by mux_unit when UL grant is received
// Periodic BSR is triggered by the expiration of the timers
void bsr_proc::step(uint32_t tti) void bsr_proc::step(uint32_t tti)
{ {
if (!initiated) { if (!initiated) {
return; return;
} }
if (!timer_periodic) {
if (params_db->get_param(mac_params::BSR_TIMER_PERIODIC)) {
timer_periodic = true;
timers_db->get(mac::BSR_TIMER_PERIODIC)->set(this, params_db->get_param(mac_params::BSR_TIMER_PERIODIC));
}
}
if (!timer_retx) {
if (params_db->get_param(mac_params::BSR_TIMER_RETX)) {
timer_retx = true;
timers_db->get(mac::BSR_TIMER_RETX)->set(this, params_db->get_param(mac_params::BSR_TIMER_RETX));
}
}
// Check condition 1 in Sec 5.4.5
if (triggered_bsr_type == NONE) {
if (check_highest_channel()) {
triggered_bsr_type = REGULAR;
}
}
} }
bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t nof_grant_bytes, uint32_t nof_padding_bytes, bsr_t *bsr)
{
bool ret = false;
if (triggered_bsr_type == NONE) {
// If enough space for at least truncated BSR
if (nof_padding_bytes >= 2) {
// Check condition 2 in Sec 5.4.5
if (check_all_channels()) {
triggered_bsr_type = PADDING;
}
}
}
if (triggered_bsr_type != NONE) {
// If no more data is pending and there is no space for MAC CE
uint32_t nof_pending_bytes = 0;
for (int i=0;i<4;i++) {
nof_pending_bytes += pending_bsr.buff_size[i];
}
// Do not include BSR CE if the UL grant can accomodate all pending data but is not sufficient
// to additionally accomodate the BSR MAC CE plus its header
uint32_t bsr_sz_plus_header = 1 + pending_bsr.format == LONG_BSR?3:1;
if (nof_pending_bytes + bsr_sz_plus_header == nof_grant_bytes) {
// if nof_pending_bytes + bsr_sz_plus_header > nof_grant_bytes, BSR has higher priority than data
return false;
}
get_pending_bsr_format(nof_padding_bytes);
// Instruct MUX unit to generate MAC CE
ret = true;
memcpy(bsr, &pending_bsr, sizeof(bsr_t));
if (timer_periodic && pending_bsr.format != TRUNC_BSR) {
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_PERIODIC)->run();
}
// Cancel all triggered BSR
triggered_bsr_type = NONE;
}
// Restart or Start ReTX timer
if (timer_retx) {
timers_db->get(mac::BSR_TIMER_RETX)->reset();
timers_db->get(mac::BSR_TIMER_RETX)->run();
}
return ret;
}
bool bsr_proc::need_to_send_sr() {
if (!sr_is_sent && triggered_bsr_type == REGULAR) {
sr_is_sent = true;
return true;
}
return false;
}
void bsr_proc::setup_lcg(uint32_t lcid, uint32_t new_lcg)
{
if (lcid < MAX_LCID && new_lcg < 4) {
lcg[lcid] = new_lcg;
}
}
void bsr_proc::set_priority(uint32_t lcid, uint32_t priority) {
if (lcid < MAX_LCID) {
priorities[lcid] = priority;
} }
} }
uint32_t bsr_proc::find_max_priority_lcid() {
uint32_t max_prio = 0, max_idx = 0;
for (int i=0;i<MAX_LCID;i++) {
if (priorities[i] > max_prio) {
max_prio = priorities[i];
max_idx = i;
}
}
return max_idx;
}
}
}

@ -24,5 +24,5 @@ FIND_PACKAGE(openLTE)
IF(UHD_FOUND AND OPENLTE_FOUND) IF(UHD_FOUND AND OPENLTE_FOUND)
INCLUDE_DIRECTORIES(${OPENLTE_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${OPENLTE_INCLUDE_DIRS})
ADD_EXECUTABLE(mac_test mac_test.cc) ADD_EXECUTABLE(mac_test mac_test.cc)
TARGET_LINK_LIBRARIES(mac_test srsapps_ue_mac srsapps_ue_phy srsapps_common srsapps_radio srslte ${OPENLTE_LIBRARIES} srslte_uhd) TARGET_LINK_LIBRARIES(mac_test srsapps_ue_mac srsapps_ue_phy srsapps_radio srslte ${OPENLTE_LIBRARIES} srslte_uhd)
ENDIF(UHD_FOUND AND OPENLTE_FOUND) ENDIF(UHD_FOUND AND OPENLTE_FOUND)

@ -63,12 +63,8 @@ typedef _Complex float cf_t;
class phy class phy
{ {
public: public:
phy() { phy();
started = false; void set();
is_sfn_synched = false;
cell_is_set = false;
phy_state = IDLE;
}
bool init(radio *radio_handler, tti_sync *ttisync, log *log_h); bool init(radio *radio_handler, tti_sync *ttisync, log *log_h);
bool init_agc(radio *radio_handler, tti_sync *ttisync, log *log_h); bool init_agc(radio *radio_handler, tti_sync *ttisync, log *log_h);
void stop(); void stop();
@ -134,7 +130,7 @@ private:
srslte_cell_t cell; srslte_cell_t cell;
bool cell_is_set; bool cell_is_set;
bool is_sfn_synched; bool is_sfn_synched;
bool started; volatile bool started;
srslte_ue_sync_t ue_sync; srslte_ue_sync_t ue_sync;
srslte_ue_mib_t ue_mib; srslte_ue_mib_t ue_mib;

@ -41,6 +41,14 @@
namespace srslte { namespace srslte {
namespace ue { namespace ue {
phy::phy()
{
started = false;
is_sfn_synched = false;
cell_is_set = false;
phy_state = IDLE;
}
bool phy::init(srslte::radio* radio_handler_, srslte::ue::tti_sync* ttisync_, log *log_h) { bool phy::init(srslte::radio* radio_handler_, srslte::ue::tti_sync* ttisync_, log *log_h) {
return init_(radio_handler_, ttisync_, log_h, false); return init_(radio_handler_, ttisync_, log_h, false);
} }

@ -643,14 +643,15 @@ void *plot_thread_run(void *arg) {
tmp_plot[i] = -80; tmp_plot[i] = -80;
} }
} }
for (i = 0; i < SRSLTE_REFSIGNAL_NUM_SF(ue_dl.cell.nof_prb,0); i++) { for (i = 0; i < 4*12*ue_dl.cell.nof_prb; i++) {
tmp_plot2[i] = 20 * log10f(cabsf(ue_dl.chest.pilot_estimates_average[0][i])); tmp_plot2[i] = 20 * log10f(cabsf(ue_dl.ce[0][i]));
if (isinf(tmp_plot2[i])) { if (isinf(tmp_plot2[i])) {
tmp_plot2[i] = -80; tmp_plot2[i] = -80;
} }
} }
plot_real_setNewData(&pce, tmp_plot2, SRSLTE_REFSIGNAL_NUM_SF(ue_dl.cell.nof_prb,0)); plot_real_setNewData(&pce, tmp_plot2, 4*12*ue_dl.cell.nof_prb);
if (!prog_args.input_file_name) { if (!prog_args.input_file_name) {
int max = srslte_vec_max_fi(ue_sync.strack.pss.conv_output_avg, ue_sync.strack.pss.frame_size+ue_sync.strack.pss.fft_size-1); int max = srslte_vec_max_fi(ue_sync.strack.pss.conv_output_avg, ue_sync.strack.pss.frame_size+ue_sync.strack.pss.fft_size-1);
srslte_vec_sc_prod_fff(ue_sync.strack.pss.conv_output_avg, srslte_vec_sc_prod_fff(ue_sync.strack.pss.conv_output_avg,
@ -662,10 +663,10 @@ void *plot_thread_run(void *arg) {
} }
#ifdef PLOT_CHEST_ARGUMENT #ifdef PLOT_CHEST_ARGUMENT
for (i = 0; i < SRSLTE_REFSIGNAL_NUM_SF(ue_dl.cell.nof_prb,0); i++) { for (i = 0; i < 2*12*ue_dl.cell.nof_prb; i++) {
tmp_plot2[i] = cargf(ue_dl.chest.pilot_estimates_average[0][i]); tmp_plot2[i] = cargf(ue_dl.ce[0][i]);
} }
plot_real_setNewData(&pce_arg, tmp_plot2, SRSLTE_REFSIGNAL_NUM_SF(ue_dl.cell.nof_prb,0)); plot_real_setNewData(&pce_arg, tmp_plot2, 2*12*ue_dl.cell.nof_prb);
#endif #endif
plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36*ue_dl.pdcch.nof_cce); plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36*ue_dl.pdcch.nof_cce);

@ -50,8 +50,8 @@
#include "srslte/ch_estimation/refsignal_dl.h" #include "srslte/ch_estimation/refsignal_dl.h"
#include "srslte/common/phy_common.h" #include "srslte/common/phy_common.h"
#define SRSLTE_CHEST_MAX_FILTER_FREQ_LEN 10 #define SRSLTE_CHEST_MAX_FILTER_FREQ_LEN 21
#define SRSLTE_CHEST_MAX_FILTER_TIME_LEN 4 #define SRSLTE_CHEST_MAX_FILTER_TIME_LEN 40
typedef struct { typedef struct {
srslte_cell_t cell; srslte_cell_t cell;

@ -52,6 +52,13 @@ SRSLTE_API void srslte_bit_unpack_vector(uint8_t *bits_packed,
SRSLTE_API uint32_t srslte_bit_unpack(uint8_t **bits, SRSLTE_API uint32_t srslte_bit_unpack(uint8_t **bits,
int nof_bits); int nof_bits);
SRSLTE_API uint64_t srslte_bit_unpack_l(uint8_t **bits,
int nof_bits);
SRSLTE_API void srslte_bit_pack_l(uint64_t value,
uint8_t **bits,
int nof_bits);
SRSLTE_API void srslte_bit_pack(uint32_t value, SRSLTE_API void srslte_bit_pack(uint32_t value,
uint8_t **bits, uint8_t **bits,
int nof_bits); int nof_bits);

@ -40,11 +40,32 @@
#include "srslte/utils/vector.h" #include "srslte/utils/vector.h"
#include "srslte/utils/convolution.h" #include "srslte/utils/convolution.h"
#define CHEST_RS_AVERAGE_TIME 2
#define CHEST_RS_AVERAGE_FREQ 3
#define NOISE_POWER_METHOD 1 // 0: Difference between noisy received and noiseless; 1: power of empty subcarriers #define NOISE_POWER_METHOD 1 // 0: Difference between noisy received and noiseless; 1: power of empty subcarriers
#define DEFAULT_FILTER_FREQ_LEN 11 // Must be odd
#define DEFAULT_FILTER_TIME_LEN 3
static void init_default_filters(srslte_chest_dl_t *q) {
float f[DEFAULT_FILTER_FREQ_LEN];
float t[DEFAULT_FILTER_TIME_LEN];
for (int i=0;i<DEFAULT_FILTER_FREQ_LEN/2+1;i++) {
f[i] = 1+i;
f[DEFAULT_FILTER_FREQ_LEN-i-1] = 1+i;
}
float norm = srslte_vec_acc_ff(f, DEFAULT_FILTER_FREQ_LEN);
srslte_vec_sc_prod_fff(f, 1.0/norm, f, DEFAULT_FILTER_FREQ_LEN);
srslte_chest_dl_set_filter_freq(q, f, DEFAULT_FILTER_FREQ_LEN);
for (int i=0;i<DEFAULT_FILTER_TIME_LEN/2+1;i++) {
t[i] = 1+i;
t[DEFAULT_FILTER_TIME_LEN-i-1] = 1+i;
}
norm = srslte_vec_acc_ff(t, DEFAULT_FILTER_TIME_LEN);
srslte_vec_sc_prod_fff(t, 1.0/norm, t, DEFAULT_FILTER_TIME_LEN);
srslte_chest_dl_set_filter_time(q, t, DEFAULT_FILTER_TIME_LEN);
}
/** 3GPP LTE Downlink channel estimator and equalizer. /** 3GPP LTE Downlink channel estimator and equalizer.
* Estimates the channel in the resource elements transmitting references and interpolates for the rest * Estimates the channel in the resource elements transmitting references and interpolates for the rest
@ -69,42 +90,28 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
goto clean_exit; goto clean_exit;
} }
q->tmp_freqavg = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); q->tmp_freqavg = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
if (!q->tmp_freqavg) { if (!q->tmp_freqavg) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * 2 * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
if (!q->tmp_noise) { if (!q->tmp_noise) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
for (int i=0;i<SRSLTE_CHEST_MAX_FILTER_TIME_LEN;i++) { q->tmp_timeavg_mult = srslte_vec_malloc(sizeof(cf_t) * 12*cell.nof_prb);
q->tmp_timeavg[i] = srslte_vec_malloc(sizeof(cf_t) * 2*cell.nof_prb);
if (!q->tmp_timeavg[i]) {
perror("malloc");
goto clean_exit;
}
bzero(q->tmp_timeavg[i], sizeof(cf_t) * 2*cell.nof_prb);
}
q->tmp_timeavg_mult = srslte_vec_malloc(sizeof(cf_t) * 2*cell.nof_prb);
if (!q->tmp_timeavg_mult) { if (!q->tmp_timeavg_mult) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
for (int i=0;i<cell.nof_ports;i++) { for (int i=0;i<cell.nof_ports;i++) {
q->pilot_estimates[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i)); q->pilot_estimates[i] = srslte_vec_malloc(2*sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i));
if (!q->pilot_estimates[i]) { if (!q->pilot_estimates[i]) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
// FIXME: There's an invalid read during rsrp estimation for this buffer
q->pilot_estimates_average[i] = srslte_vec_malloc(2 * sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i));
if (!q->pilot_estimates_average[i]) {
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i)); q->pilot_recv_signal[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i));
if (!q->pilot_recv_signal[i]) { if (!q->pilot_recv_signal[i]) {
perror("malloc"); perror("malloc");
@ -122,15 +129,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
goto clean_exit; goto clean_exit;
} }
/* Set default time/freq filters */ init_default_filters(q);
//float f[3]={0.2, 0.6, 0.2};
//srslte_chest_dl_set_filter_freq(q, f, 3);
float f[9]={0.025, 0.075, 0.05, 0.15, 0.4, 0.15, 0.05, 0.075, 0.025};
srslte_chest_dl_set_filter_freq(q, f, 9);
//srslte_chest_dl_set_filter_time_ema(q, 0.8);
q->cell = cell; q->cell = cell;
} }
@ -153,11 +152,6 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
if (q->tmp_noise) { if (q->tmp_noise) {
free(q->tmp_noise); free(q->tmp_noise);
} }
for (int i=0;i<SRSLTE_CHEST_MAX_FILTER_TIME_LEN;i++) {
if (q->tmp_timeavg[i]) {
free(q->tmp_timeavg[i]);
}
}
if (q->tmp_timeavg_mult) { if (q->tmp_timeavg_mult) {
free(q->tmp_timeavg_mult); free(q->tmp_timeavg_mult);
} }
@ -168,9 +162,6 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
if (q->pilot_estimates[i]) { if (q->pilot_estimates[i]) {
free(q->pilot_estimates[i]); free(q->pilot_estimates[i]);
} }
if (q->pilot_estimates_average[i]) {
free(q->pilot_estimates_average[i]);
}
if (q->pilot_recv_signal[i]) { if (q->pilot_recv_signal[i]) {
free(q->pilot_recv_signal[i]); free(q->pilot_recv_signal[i]);
} }
@ -209,14 +200,11 @@ int srslte_chest_dl_set_filter_time(srslte_chest_dl_t *q, float *filter, uint32_
#if NOISE_POWER_METHOD==0 #if NOISE_POWER_METHOD==0
/* 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_port(srslte_chest_dl_t *q, uint32_t port_id, cf_t *avg_pilots) { static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *average, cf_t *ce, uint32_t len) {
/* Use difference between averaged and noisy LS pilot estimates */ /* Use difference between averaged and noisy LS pilot estimates */
srslte_vec_sub_ccc(avg_pilots, q->pilot_estimates[port_id], srslte_vec_sub_ccc(average, ce, q->tmp_noise, len);
q->tmp_noise, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); return srslte_vec_avg_power_cf(q->tmp_noise, len);
return srslte_vec_avg_power_cf(q->tmp_noise, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
} }
#endif #endif
@ -236,97 +224,52 @@ static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *input) {
} }
#endif #endif
#define pilot_est(idx) q->pilot_estimates[port_id][SRSLTE_REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
#define pilot_avg(idx) q->pilot_estimates_average[port_id][SRSLTE_REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
#define pilot_tmp(idx) q->tmp_freqavg[SRSLTE_REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
static void average_pilots(srslte_chest_dl_t *q, uint32_t port_id) static void average_estimates(srslte_chest_dl_t *q, cf_t *ce, uint32_t port_id)
{ {
int nref=2*q->cell.nof_prb; int nref=12*q->cell.nof_prb;
uint32_t l, i; uint32_t l, i;
/* For each symbol with pilots in a slot */ /* For each symbol with pilots in a slot */
for (l=0;l<srslte_refsignal_cs_nof_symbols(port_id);l++) { for (l=0;l<SRSLTE_CP_NSYMB(q->cell.cp);l++) {
if (q->filter_freq_len > 0) { if (q->filter_freq_len > 0) {
/* Filter pilot estimates in frequency */ /* Filter pilot estimates in frequency */
srslte_conv_same_cf(&pilot_est(0), q->filter_freq, &pilot_tmp(0), nref, q->filter_freq_len); srslte_conv_same_cf(&ce[l*12*q->cell.nof_prb], q->filter_freq, &q->tmp_freqavg[l*12*q->cell.nof_prb], nref, q->filter_freq_len);
/* Adjust extremes using linear interpolation */
pilot_tmp(0) += srslte_interp_linear_onesample(pilot_est(1), pilot_est(0))
* q->filter_freq[q->filter_freq_len/2-1]*1.2;
pilot_tmp(nref-1) += srslte_interp_linear_onesample(pilot_est(nref-2), pilot_est(nref-1))
* q->filter_freq[q->filter_freq_len/2+1]*1.2;
} else { } else {
memcpy(&pilot_tmp(0), &pilot_est(0), nref * sizeof(cf_t)); memcpy(&q->tmp_freqavg[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref * sizeof(cf_t));
} }
} }
#if NOISE_POWER_METHOD==0 #if NOISE_POWER_METHOD==0
q->noise_estimate[port_id] = estimate_noise_port(q, port_id, q->tmp_freqavg); q->noise_estimate[port_id] = estimate_noise_port(q, q->tmp_freqavg, ce,
SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp));
#endif #endif
/* Filter with FIR or don't filter */
//#define EMA_VEC for (l=0;l<SRSLTE_CP_NSYMB(q->cell.cp);l++) {
/* Filter in time domain. */
/* Filter with Exponential moving average (IIR) */ if (q->filter_time_len > 0) {
if (q->filter_time_ema > 0) { /* Multiply symbols by filter and add them */
#ifdef EMA_VEC bzero(&ce[l*12*q->cell.nof_prb], nref * sizeof(cf_t));
srslte_vec_ema_filter(&q->tmp_freqavg[0], for (i=0;i<q->filter_time_len;i++) {
&q->pilot_estimates_average[port_id][2*q->cell.nof_prb*srslte_refsignal_cs_nof_symbols(port_id)], if (l+i-q->filter_time_len/2 < SRSLTE_CP_NSYMB(q->cell.cp) && l+i-q->filter_time_len/2 > 0) {
&q->pilot_estimates_average[port_id][0], srslte_vec_sc_prod_cfc(&q->tmp_freqavg[(l+i-q->filter_time_len/2)*12*q->cell.nof_prb], q->filter_time[i], q->tmp_timeavg_mult, nref);
q->filter_time_ema, srslte_vec_sum_ccc(q->tmp_timeavg_mult, &ce[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref);
nref);
for (l=1;l<srslte_refsignal_cs_nof_symbols(port_id);l++) {
srslte_vec_ema_filter(&q->tmp_freqavg[2*q->cell.nof_prb*l],
&q->pilot_estimates_average[port_id][2*q->cell.nof_prb*(l-1)],
&q->pilot_estimates_average[port_id][2*q->cell.nof_prb*l],
q->filter_time_ema,
nref);
}
#else
for (i=0;i<nref;i++) {
l=0;
pilot_avg(i) = SRSLTE_VEC_EMA(pilot_tmp(i), q->pilot_estimates_average[port_id][
SRSLTE_REFSIGNAL_PILOT_IDX(i,srslte_refsignal_cs_nof_symbols(port_id),q->cell)], q->filter_time_ema);
for (l=1;l<srslte_refsignal_cs_nof_symbols(port_id);l++) {
pilot_avg(i) = SRSLTE_VEC_EMA(pilot_tmp(i), q->pilot_estimates_average[port_id][SRSLTE_REFSIGNAL_PILOT_IDX(i,l-1,q->cell)], q->filter_time_ema);
}
}
#endif
} else {
/* Filter with FIR or don't filter */
for (l=0;l<srslte_refsignal_cs_nof_symbols(port_id);l++) {
/* Filter in time domain. */
if (q->filter_time_len > 0) {
/* Move last symbols */
for (i=0;i<q->filter_time_len-1;i++) {
memcpy(q->tmp_timeavg[i], q->tmp_timeavg[i+1], nref*sizeof(cf_t));
}
/* Save last symbol to buffer */
memcpy(q->tmp_timeavg[q->filter_time_len-1], &pilot_tmp(0), nref*sizeof(cf_t));
/* Multiply all symbols by filter and add them */
if (l > 0) {
bzero(&pilot_avg(0), nref * sizeof(cf_t));
for (i=0;i<q->filter_time_len;i++) {
srslte_vec_sc_prod_cfc(q->tmp_timeavg[i], q->filter_time[i], q->tmp_timeavg_mult, nref);
srslte_vec_sum_ccc(q->tmp_timeavg_mult, &pilot_avg(0), &pilot_avg(0), nref);
}
} else { } else {
memcpy(&pilot_avg(0), &pilot_tmp(0), nref * sizeof(cf_t)); srslte_vec_sc_prod_cfc(&q->tmp_freqavg[l*12*q->cell.nof_prb], q->filter_time[i], q->tmp_timeavg_mult, nref);
srslte_vec_sum_ccc(q->tmp_timeavg_mult, &ce[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref);
} }
} else {
memcpy(&pilot_avg(0), &pilot_tmp(0), nref * sizeof(cf_t));
} }
} else {
memcpy(&ce[l*12*q->cell.nof_prb], &q->tmp_freqavg[l*12*q->cell.nof_prb], nref * sizeof(cf_t));
} }
} }
} }
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *ce, uint32_t port_id) static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id)
{ {
/* interpolate the symbols with references in the freq domain */ /* interpolate the symbols with references in the freq domain */
uint32_t l; uint32_t l;
@ -335,7 +278,7 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *ce, uint32_t port_id)
/* Interpolate in the frequency domain */ /* Interpolate in the frequency domain */
for (l=0;l<nsymbols;l++) { for (l=0;l<nsymbols;l++) {
uint32_t fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); uint32_t fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_avg(0), srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/2-fidx_offset); fidx_offset, SRSLTE_NRE/2-fidx_offset);
} }
@ -399,8 +342,13 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u
srslte_vec_prod_conj_ccc(q->pilot_recv_signal[port_id], q->csr_signal.pilots[port_id/2][sf_idx], srslte_vec_prod_conj_ccc(q->pilot_recv_signal[port_id], q->csr_signal.pilots[port_id/2][sf_idx],
q->pilot_estimates[port_id], SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); q->pilot_estimates[port_id], SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
/* Average pilot estimates */ if (ce != NULL) {
average_pilots(q, port_id); /* Interpolate to create channel estimates for all resource grid */
interpolate_pilots(q, q->pilot_estimates[port_id], ce, port_id);
/* Average channel estimates */
average_estimates(q, ce, port_id);
}
#if NOISE_POWER_METHOD==1 #if NOISE_POWER_METHOD==1
q->noise_estimate[port_id] = estimate_noise_port(q, input); q->noise_estimate[port_id] = estimate_noise_port(q, input);
@ -413,11 +361,6 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u
q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id); q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id);
} }
/* Interpolate to create channel estimates for all resource grid */
if (ce != NULL) {
interpolate_pilots(q, ce, port_id);
}
return 0; return 0;
} }

@ -201,7 +201,7 @@ int main(int argc, char **argv) {
mse /= num_re; mse /= num_re;
printf("MSE: %f\n", mse); printf("MSE: %f\n", mse);
if (mse > 1.7) { if (mse > 2.0) {
goto do_exit; goto do_exit;
} }

@ -72,11 +72,6 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
double *outr1=NULL, *outi1=NULL; double *outr1=NULL, *outi1=NULL;
double *outr2=NULL, *outi2=NULL; double *outr2=NULL, *outi2=NULL;
if (nrhs < NOF_INPUTS) {
help();
return;
}
if (!mxIsDouble(CELLID) && mxGetN(CELLID) != 1 && if (!mxIsDouble(CELLID) && mxGetN(CELLID) != 1 &&
!mxIsDouble(PORTS) && mxGetN(PORTS) != 1 && !mxIsDouble(PORTS) && mxGetN(PORTS) != 1 &&
mxGetM(CELLID) != 1) { mxGetM(CELLID) != 1) {
@ -117,34 +112,30 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
return; return;
} }
sf_idx = (uint32_t) *((double*) mxGetPr(SFIDX)); sf_idx = (uint32_t) *((double*) mxGetPr(SFIDX));
} else {
if (nrhs != NOF_INPUTS) {
help();
return;
}
} }
uint32_t filter_len = 0; if (nrhs > 5) {
float *filter; uint32_t filter_len = 0;
double *f; float *filter;
double *f;
filter_len = mxGetNumberOfElements(FREQ_FILTER); filter_len = mxGetNumberOfElements(FREQ_FILTER);
filter = malloc(sizeof(float) * filter_len); filter = malloc(sizeof(float) * filter_len);
f = (double*) mxGetPr(FREQ_FILTER); f = (double*) mxGetPr(FREQ_FILTER);
for (i=0;i<filter_len;i++) { for (i=0;i<filter_len;i++) {
filter[i] = (float) f[i]; filter[i] = (float) f[i];
} }
srslte_chest_dl_set_filter_freq(&chest, filter, filter_len); srslte_chest_dl_set_filter_freq(&chest, filter, filter_len);
filter_len = mxGetNumberOfElements(TIME_FILTER); filter_len = mxGetNumberOfElements(TIME_FILTER);
filter = malloc(sizeof(float) * filter_len); filter = malloc(sizeof(float) * filter_len);
f = (double*) mxGetPr(TIME_FILTER); f = (double*) mxGetPr(TIME_FILTER);
for (i=0;i<filter_len;i++) { for (i=0;i<filter_len;i++) {
filter[i] = (float) f[i]; filter[i] = (float) f[i];
}
srslte_chest_dl_set_filter_time(&chest, filter, filter_len);
} }
srslte_chest_dl_set_filter_time(&chest, filter, filter_len);
double *inr=(double *)mxGetPr(INPUT); double *inr=(double *)mxGetPr(INPUT);

@ -43,6 +43,16 @@ void srslte_bit_pack_vector(uint8_t *bits_unpacked, uint8_t *bits_packed, int no
} }
} }
void srslte_bit_pack_l(uint64_t value, uint8_t **bits, int nof_bits)
{
int i;
for(i=0; i<nof_bits; i++) {
(*bits)[i] = (value >> (nof_bits-i-1)) & 0x1;
}
*bits += nof_bits;
}
void srslte_bit_pack(uint32_t value, uint8_t **bits, int nof_bits) void srslte_bit_pack(uint32_t value, uint8_t **bits, int nof_bits)
{ {
int i; int i;
@ -77,6 +87,18 @@ uint32_t srslte_bit_unpack(uint8_t **bits, int nof_bits)
return value; return value;
} }
uint64_t srslte_bit_unpack_l(uint8_t **bits, int nof_bits)
{
int i;
uint64_t value=0;
for(i=0; i<nof_bits; i++) {
value |= (*bits)[i] << (nof_bits-i-1);
}
*bits += nof_bits;
return value;
}
void srslte_bit_fprint(FILE *stream, uint8_t *bits, int nof_bits) { void srslte_bit_fprint(FILE *stream, uint8_t *bits, int nof_bits) {
int i; int i;

@ -124,6 +124,49 @@ uint32_t srslte_conv_same_cc(cf_t *input, cf_t *filter, cf_t *output, uint32_t i
return N; return N;
} }
#define conv_same_extrapolates_extremes
#ifdef conv_same_extrapolates_extremes
uint32_t srslte_conv_same_cf(cf_t *input, float *filter, cf_t *output,
uint32_t input_len, uint32_t filter_len) {
uint32_t i;
uint32_t M = filter_len;
uint32_t N = input_len;
cf_t first[filter_len+filter_len/2];
cf_t last[filter_len+filter_len/2];
for (i=0;i<M+M/2;i++) {
if (i<M/2) {
first[i] = (2+M/2-i)*input[1]-(1+M/2-i)*input[0];
} else {
first[i] = input[i-M/2];
}
}
for (i=0;i<M+M/2;i++) {
if (i>=M-1) {
last[i] = (2+i-M/2)*input[N-1]-(1+i-M/2)*input[N-2];
} else {
last[i] = input[N-M+i+1];
}
}
for (i=0;i<M/2;i++) {
output[i]=srslte_vec_dot_prod_cfc(&first[i],filter,M);
}
for (;i<N-M/2;i++) {
output[i]=srslte_vec_dot_prod_cfc(&input[i-M/2],filter,M);
}
int j=0;
for (;i<N;i++) {
output[i]=srslte_vec_dot_prod_cfc(&last[j++],filter,M);
}
return N;
}
#else
uint32_t srslte_conv_same_cf(cf_t *input, float *filter, cf_t *output, uint32_t srslte_conv_same_cf(cf_t *input, float *filter, cf_t *output,
uint32_t input_len, uint32_t filter_len) { uint32_t input_len, uint32_t filter_len) {
uint32_t i; uint32_t i;
@ -141,3 +184,5 @@ uint32_t srslte_conv_same_cf(cf_t *input, float *filter, cf_t *output,
} }
return N; return N;
} }
#endif
Loading…
Cancel
Save