Added pre/post padding for TX bursts.

This commit is contained in:
ismagom 2015-06-05 22:31:28 +02:00
parent 3f871a14a3
commit e093b3a7de
12 changed files with 121 additions and 49 deletions

View File

@ -42,6 +42,7 @@ namespace srslte {
public: public:
virtual void get_time(srslte_timestamp_t *now) = 0; virtual void get_time(srslte_timestamp_t *now) = 0;
virtual bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) = 0; virtual bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) = 0;
virtual bool tx_end() = 0;
virtual bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time) = 0; virtual bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time) = 0;
virtual bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) = 0; virtual bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) = 0;

View File

@ -49,6 +49,7 @@ namespace srslte {
void get_time(srslte_timestamp_t *now); void get_time(srslte_timestamp_t *now);
bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool tx_end();
bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time); bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time);
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
@ -72,7 +73,17 @@ namespace srslte {
private: private:
void *uhd; void *uhd;
bool is_first;
static const double lo_offset = 8e6; // LO offset (in Hz)
static const double burst_settle_time = 0.4e-3; // Start of burst settle time (off->on RF transition time)
const static uint32_t burst_settle_max_samples = 12288; // 30.72 MHz is maximum frequency
srslte_timestamp_t end_of_burst_time;
bool is_start_of_burst;
uint32_t burst_settle_samples;
double burst_settle_time_rounded; // settle time rounded to sample time
cf_t zeros[burst_settle_max_samples];
double cur_tx_srate;
}; };
} }

View File

@ -28,7 +28,6 @@
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srsapps/radio/radio_uhd.h" #include "srsapps/radio/radio_uhd.h"
namespace srslte { namespace srslte {
bool radio_uhd::init() bool radio_uhd::init()
@ -57,7 +56,6 @@ void radio_uhd::set_tx_rx_gain_offset(float offset) {
bool radio_uhd::init_agc(char *args) bool radio_uhd::init_agc(char *args)
{ {
is_first = true;
printf("Opening UHD device with threaded RX Gain control ...\n"); printf("Opening UHD device with threaded RX Gain control ...\n");
if (cuhd_open_th(args, &uhd, true)) { if (cuhd_open_th(args, &uhd, true)) {
fprintf(stderr, "Error opening uhd\n"); fprintf(stderr, "Error opening uhd\n");
@ -65,6 +63,11 @@ bool radio_uhd::init_agc(char *args)
} }
cuhd_set_rx_gain(uhd, 40); cuhd_set_rx_gain(uhd, 40);
cuhd_set_tx_gain(uhd, 40); cuhd_set_tx_gain(uhd, 40);
burst_settle_samples = 0;
burst_settle_time_rounded = 0;
is_start_of_burst = true;
return true; return true;
} }
bool radio_uhd::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) bool radio_uhd::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time)
@ -88,14 +91,31 @@ void radio_uhd::get_time(srslte_timestamp_t *now) {
bool radio_uhd::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) bool radio_uhd::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
{ {
if (cuhd_send_timed2(uhd, buffer, nof_samples, tx_time.full_secs, tx_time.frac_secs, is_first, false) > 0) { if (is_start_of_burst) {
is_first = false; if (burst_settle_samples != 0) {
srslte_timestamp_t tx_time_pad;
srslte_timestamp_copy(&tx_time_pad, &tx_time);
srslte_timestamp_sub(&tx_time_pad, 0, burst_settle_time_rounded);
cuhd_send_timed2(uhd, zeros, burst_settle_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, false);
}
is_start_of_burst = false;
srslte_timestamp_copy(&end_of_burst_time, &tx_time);
srslte_timestamp_add(&end_of_burst_time, 0, nof_samples*cur_tx_srate);
}
if (cuhd_send_timed2(uhd, buffer, nof_samples, tx_time.full_secs, tx_time.frac_secs, false, false) > 0) {
return true; return true;
} else { } else {
return false; return false;
} }
} }
bool radio_uhd::tx_end()
{
cuhd_send_timed2(uhd, zeros, burst_settle_samples, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, true);
is_start_of_burst = true;
}
void radio_uhd::set_rx_freq(float freq) void radio_uhd::set_rx_freq(float freq)
{ {
cuhd_set_rx_freq(uhd, freq); cuhd_set_rx_freq(uhd, freq);
@ -118,8 +138,7 @@ void radio_uhd::set_rx_srate(float srate)
void radio_uhd::set_tx_freq(float freq) void radio_uhd::set_tx_freq(float freq)
{ {
//cuhd_set_tx_freq(uhd, freq); cuhd_set_tx_freq_offset(uhd, freq, lo_offset);
cuhd_set_tx_freq_offset(uhd, freq, 8e6);
} }
void radio_uhd::set_tx_gain(float gain) void radio_uhd::set_tx_gain(float gain)
@ -139,7 +158,13 @@ float radio_uhd::get_rx_gain()
void radio_uhd::set_tx_srate(float srate) void radio_uhd::set_tx_srate(float srate)
{ {
cuhd_set_tx_srate(uhd, srate); cur_tx_srate = cuhd_set_tx_srate(uhd, srate);
burst_settle_samples = (uint32_t) (cur_tx_srate * burst_settle_time);
if (burst_settle_samples > burst_settle_max_samples) {
burst_settle_samples = burst_settle_max_samples;
fprintf(stderr, "Error setting TX srate %.1f MHz. Maximum frequency for zero prepadding is 30.72 MHz\n", srate*1e-6);
}
burst_settle_time_rounded = (double) burst_settle_samples/cur_tx_srate;
} }
void radio_uhd::start_rx() void radio_uhd::start_rx()

View File

@ -167,6 +167,8 @@ private:
float old_gain; float old_gain;
uint32_t sr_tx_tti; uint32_t sr_tx_tti;
bool is_first_of_burst;
}; };
} }

View File

@ -59,11 +59,9 @@ namespace ue {
bool generate_data(); bool generate_data();
bool generate_data(ul_sched_grant *pusch_grant, uint8_t *payload); bool generate_data(ul_sched_grant *pusch_grant, uint8_t *payload);
bool generate_data(ul_sched_grant *pusch_grant, srslte_softbuffer_tx_t *softbuffer, uint8_t *payload); bool generate_data(ul_sched_grant *pusch_grant, srslte_softbuffer_tx_t *softbuffer, uint8_t *payload);
bool send(radio* radio_handler, float time_adv_sec, float cfo, srslte_timestamp_t rx_time, bool normalize_amp);
bool send(radio* radio_handler, float time_adv_sec, float cfo, srslte_timestamp_t rx_time); bool send(radio* radio_handler, float time_adv_sec, float cfo, srslte_timestamp_t rx_time);
bool send_zeros(radio* radio_handler, float time_adv_sec, srslte_timestamp_t rx_time);
static const uint32_t tx_advance_sf = 1; // Number of subframes to advance transmission static const uint32_t tx_advance_sf = 1; // Number of subframes to advance transmission
static const bool normalize_amp = true;
private: private:
log *log_h; log *log_h;
phy_params *params_db; phy_params *params_db;

View File

@ -74,6 +74,7 @@ bool phy::init_(srslte::radio* radio_handler_, srslte::ue::tti_sync* ttisync_, l
dl_buffer_queue = new queue(6, sizeof(dl_buffer)); dl_buffer_queue = new queue(6, sizeof(dl_buffer));
do_agc = do_agc_; do_agc = do_agc_;
last_gain = 1e4; last_gain = 1e4;
time_adv_sec = 0;
// Set default params // Set default params
params_db.set_param(phy_params::CELLSEARCH_TIMEOUT_PSS_NFRAMES, 100); params_db.set_param(phy_params::CELLSEARCH_TIMEOUT_PSS_NFRAMES, 100);
@ -143,8 +144,8 @@ bool phy::send_prach(uint32_t preamble_idx, int allowed_subframe, int target_pow
if (phy_state == RXTX) { if (phy_state == RXTX) {
srslte_agc_lock(&ue_sync.agc, true); srslte_agc_lock(&ue_sync.agc, true);
old_gain = radio_handler->get_tx_gain(); old_gain = radio_handler->get_tx_gain();
radio_handler->set_tx_gain(0); radio_handler->set_tx_gain(10);
Info("Stopped AGC. Set TX gain to %.1f dB\n", 0); Info("Stopped AGC. Set TX gain to %.1f dB\n", radio_handler->get_tx_gain());
return prach_buffer.prepare_to_send(preamble_idx, allowed_subframe, target_power_dbm); return prach_buffer.prepare_to_send(preamble_idx, allowed_subframe, target_power_dbm);
} }
return false; return false;
@ -508,7 +509,8 @@ void phy::run_rx_tx_state()
phy_state = IDLE; phy_state = IDLE;
break; break;
case 1: case 1:
is_sfn_synched = true; is_sfn_synched = true;
is_first_of_burst = true;
break; break;
case 0: case 0:
break; break;
@ -520,7 +522,7 @@ void phy::run_rx_tx_state()
bool tx_zeros = true; bool tx_zeros = true;
// Prepare transmission for the next tti // Advance transmission time for the next tti
srslte_timestamp_add(&last_rx_time, 0, 1e-3); srslte_timestamp_add(&last_rx_time, 0, 1e-3);
// Generate scheduling request if we have to // Generate scheduling request if we have to
@ -543,17 +545,15 @@ void phy::run_rx_tx_state()
get_ul_buffer_adv(current_tti)->generate_data(); get_ul_buffer_adv(current_tti)->generate_data();
} }
// And transmit // And transmit
get_ul_buffer_adv(current_tti)->send(radio_handler, time_adv_sec, cfo, last_rx_time); get_ul_buffer_adv(current_tti)->send(radio_handler, time_adv_sec, cfo, last_rx_time);
is_first_of_burst = false;
} else { } else {
// Transmit zeros to avoid transitions. if (!is_first_of_burst) {
// FIXME: This keeps the TX RF chain always on. Should transmit zeros only before a true transmission radio_handler->tx_end();
get_ul_buffer_adv(current_tti)->send_zeros(radio_handler, time_adv_sec, last_rx_time); is_first_of_burst = true;
}
} }
// send ul buffer if we have to
// Generate PUCCH if no UL grant
// Receive alligned buffer for the current tti // Receive alligned buffer for the current tti
get_dl_buffer(current_tti)->recv_ue_sync(&ue_sync, &last_rx_time); get_dl_buffer(current_tti)->recv_ue_sync(&ue_sync, &last_rx_time);

View File

@ -160,7 +160,6 @@ bool prach::send(radio *radio_handler, float cfo, srslte_timestamp_t rx_time)
} }
} }
// transmit
radio_handler->tx(signal_buffer, len, tx_time); radio_handler->tx(signal_buffer, len, tx_time);
Info("PRACH transmitted CFO: %f, preamble=%d, len=%d rx_time=%f, tx_time=%f, PeakAmplitude=%.2f\n", Info("PRACH transmitted CFO: %f, preamble=%d, len=%d rx_time=%f, tx_time=%f, PeakAmplitude=%.2f\n",
cfo*15000, preamble_idx, len, rx_time.frac_secs, tx_time.frac_secs, max); cfo*15000, preamble_idx, len, rx_time.frac_secs, tx_time.frac_secs, max);

View File

@ -49,7 +49,7 @@ bool ul_buffer::init_cell(srslte_cell_t cell_, phy_params *params_db_, log *log_
if (!srslte_ue_ul_init(&ue_ul, cell)) { if (!srslte_ue_ul_init(&ue_ul, cell)) {
srslte_ue_ul_set_normalization(&ue_ul, false); srslte_ue_ul_set_normalization(&ue_ul, false);
signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
cell_initiated = signal_buffer?true:false; cell_initiated = (signal_buffer)?true:false;
srslte_ue_ul_set_cfo_enable(&ue_ul, false); srslte_ue_ul_set_cfo_enable(&ue_ul, false);
bzero(&uci_data, sizeof(srslte_uci_data_t)); bzero(&uci_data, sizeof(srslte_uci_data_t));
uci_pending = false; uci_pending = false;
@ -218,21 +218,9 @@ bool ul_buffer::generate_data(ul_sched_grant *grant, srslte_softbuffer_tx_t *sof
int nof_tx = 0; int nof_tx = 0;
bool ul_buffer::send_zeros(srslte::radio* radio_handler, float time_adv_sec, srslte_timestamp_t rx_time)
{
bzero(signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
send(radio_handler, time_adv_sec, 0, rx_time, false);
}
bool ul_buffer::send(srslte::radio* radio_handler, float time_adv_sec, float cfo, srslte_timestamp_t rx_time) bool ul_buffer::send(srslte::radio* radio_handler, float time_adv_sec, float cfo, srslte_timestamp_t rx_time)
{ {
send(radio_handler, time_adv_sec, cfo, rx_time, true); // send packet next timeslot minus time advance
}
bool ul_buffer::send(srslte::radio* radio_handler, float time_adv_sec, float cfo, srslte_timestamp_t rx_time, bool normalize_amp)
{
// send packet through usrp
srslte_timestamp_t tx_time; srslte_timestamp_t tx_time;
srslte_timestamp_copy(&tx_time, &rx_time); srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_add(&tx_time, 0, tx_advance_sf*1e-3 - time_adv_sec); srslte_timestamp_add(&tx_time, 0, tx_advance_sf*1e-3 - time_adv_sec);
@ -256,7 +244,7 @@ bool ul_buffer::send(srslte::radio* radio_handler, float time_adv_sec, float cfo
srslte_vec_sc_prod_cfc(signal_buffer, 0.9/max, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); srslte_vec_sc_prod_cfc(signal_buffer, 0.9/max, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb));
} }
Info("TX CFO: %f, len=%d, rx_time= %.6f tx_time = %.6f TA: %.1f us PeakAmplitude=%.2f PKT#%d\n", Info("TX CFO: %f, len=%d, rx_time= %.6f tx_time = %.6f TA: %.1f PeakAmplitude=%.2f PKT#%d\n",
cfo*15000, SRSLTE_SF_LEN_PRB(cell.nof_prb), cfo*15000, SRSLTE_SF_LEN_PRB(cell.nof_prb),
srslte_timestamp_real(&rx_time), srslte_timestamp_real(&rx_time),
srslte_timestamp_real(&tx_time), time_adv_sec*1000000, max, nof_tx); srslte_timestamp_real(&tx_time), time_adv_sec*1000000, max, nof_tx);

View File

@ -98,6 +98,7 @@ int main(int argc, char **argv) {
parse_args(argc, argv); parse_args(argc, argv);
uint32_t flen = srslte_sampling_freq_hz(nof_prb)/1000; uint32_t flen = srslte_sampling_freq_hz(nof_prb)/1000;
uint32_t nsamples_adv = 3000;
cf_t *rx_buffer = malloc(sizeof(cf_t)*flen*nof_frames); cf_t *rx_buffer = malloc(sizeof(cf_t)*flen*nof_frames);
if (!rx_buffer) { if (!rx_buffer) {
@ -105,11 +106,13 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
cf_t *tx_buffer = malloc(sizeof(cf_t)*flen); cf_t *tx_buffer = malloc(sizeof(cf_t)*(flen+nsamples_adv));
if (!tx_buffer) { if (!tx_buffer) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
bzero(tx_buffer, sizeof(cf_t)*(flen+nsamples_adv));
cf_t *zeros = calloc(sizeof(cf_t),flen); cf_t *zeros = calloc(sizeof(cf_t),flen);
if (!zeros) { if (!zeros) {
perror("calloc"); perror("calloc");
@ -132,24 +135,28 @@ int main(int argc, char **argv) {
cuhd_set_tx_freq_offset(uhd, uhd_freq, 8e6); cuhd_set_tx_freq_offset(uhd, uhd_freq, 8e6);
sleep(1); sleep(1);
srslte_vec_load_file(input_filename, tx_buffer, flen*sizeof(cf_t)); srslte_vec_load_file(input_filename, &tx_buffer[nsamples_adv], flen*sizeof(cf_t));
srslte_timestamp_t tstamp; srslte_timestamp_t tstamp;
cuhd_start_rx_stream(uhd); cuhd_start_rx_stream(uhd);
uint32_t nframe=0; uint32_t nframe=0;
float burst_settle_time = (float) nsamples_adv/srslte_sampling_freq_hz(nof_prb);
printf("timeadv=%f\n",burst_settle_time);
while(nframe<nof_frames) { while(nframe<nof_frames) {
printf("Rx subframe %d\n", nframe); printf("Rx subframe %d\n", nframe);
cuhd_recv_with_time(uhd, &rx_buffer[flen*nframe], flen, true, &tstamp.full_secs, &tstamp.frac_secs); cuhd_recv_with_time(uhd, &rx_buffer[flen*nframe], flen, true, &tstamp.full_secs, &tstamp.frac_secs);
nframe++; nframe++;
if (nframe==9 || nframe==8) { if (nframe==9 || nframe==8) {
srslte_timestamp_add(&tstamp, 0, 2e-3); srslte_timestamp_add(&tstamp, 0, 2e-3-burst_settle_time);
if (nframe==8) { if (nframe==8) {
cuhd_send_timed2(uhd, zeros, flen, tstamp.full_secs, tstamp.frac_secs, true, false); //cuhd_send_timed2(uhd, zeros, flen, tstamp.full_secs, tstamp.frac_secs, true, false);
printf("Transmitting zeros\n"); printf("Transmitting zeros\n");
} else { } else {
cuhd_send_timed2(uhd, tx_buffer, flen, tstamp.full_secs, tstamp.frac_secs, false, true); cuhd_send_timed2(uhd, tx_buffer, flen+nsamples_adv, tstamp.full_secs, tstamp.frac_secs, true, true);
printf("Transmitting Signal\n"); printf("Transmitting Signal\n");
} }
} }

View File

@ -149,4 +149,10 @@ SRSLTE_API void srslte_ue_ul_reset(srslte_ue_ul_t *q);
SRSLTE_API void srslte_ue_ul_set_rnti(srslte_ue_ul_t *q, SRSLTE_API void srslte_ue_ul_set_rnti(srslte_ue_ul_t *q,
uint16_t rnti); uint16_t rnti);
/* Other static functions for UL PHY procedures defined in 36.213 */
SRSLTE_API int srslte_ue_ul_sr_config(uint32_t I_sr,
uint32_t *sr_periodicity,
uint32_t *sr_N_offset);
#endif #endif

View File

@ -162,7 +162,7 @@ int cuhd_open_(char *args, void **h, bool create_thread_gain, bool tx_gain_same_
{ {
cuhd_handler *handler = new cuhd_handler(); cuhd_handler *handler = new cuhd_handler();
std::string _args = std::string(args); std::string _args = std::string(args);
handler->usrp = uhd::usrp::multi_usrp::make(_args);// + ", master_clock_rate=30720000, num_recv_frames=512"); handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000, num_recv_frames=512");
// handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512"); // handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512");
handler->usrp->set_clock_source("internal"); handler->usrp->set_clock_source("internal");

View File

@ -374,6 +374,41 @@ int srslte_ue_ul_pusch_encode_cfg(srslte_ue_ul_t *q, srslte_pusch_cfg_t *cfg,
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
return ret; return ret;
}
}
/* Obtains Scheduling Request channel assignment as defined in Table 10.1-5, 36.213 */
int srslte_ue_ul_sr_config(uint32_t I_sr, uint32_t *sr_periodicity, uint32_t *sr_N_offset) {
if (sr_periodicity && sr_N_offset) {
if (I_sr < 5) {
*sr_periodicity = 5;
*sr_N_offset = I_sr;
} else if (I_sr < 15) {
*sr_periodicity = 10;
*sr_N_offset = I_sr-5;
} else if (I_sr < 35) {
*sr_periodicity = 20;
*sr_N_offset = I_sr-15;
} else if (I_sr < 75) {
*sr_periodicity = 40;
*sr_N_offset = I_sr-35;
} else if (I_sr < 155) {
*sr_periodicity = 80;
*sr_N_offset = I_sr-75;
} else if (I_sr < 157) {
*sr_periodicity = 2;
*sr_N_offset = I_sr-155;
} else if (I_sr == 157) {
*sr_periodicity = 1;
*sr_N_offset = I_sr-157;
} else {
return SRSLTE_ERROR;
}
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
return SRSLTE_SUCCESS;
}