Improved UE measurements. Calibrated for gain 40 dB

This commit is contained in:
ismagom 2014-11-26 17:24:10 +00:00
parent 632e841dbe
commit 445fc639e8
8 changed files with 82 additions and 63 deletions

View File

@ -41,6 +41,11 @@
#include "liblte/cuhd/cuhd.h"
#include "cell_search_utils.h"
#define B210_DEFAULT_GAIN 40.0
#define B210_DEFAULT_GAIN_CORREC 76.0 // Gain of the Rx chain when the gain is set to 40
float gain_offset = B210_DEFAULT_GAIN_CORREC;
cell_detect_cfg_t cell_detect_config = {
500, // nof_frames_total
50, // nof_frames_detected
@ -64,7 +69,7 @@ void args_default(prog_args_t *args) {
args->force_N_id_2 = -1; // Pick the best
args->uhd_args = "";
args->uhd_freq = -1.0;
args->uhd_gain = 60.0;
args->uhd_gain = B210_DEFAULT_GAIN;
}
void usage(prog_args_t *args, char *prog) {
@ -141,7 +146,7 @@ int main(int argc, char **argv) {
int n;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
uint32_t sfn_offset;
float rssi=0, rsrp=0, rsrq=0, snr=0;
float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0;
cf_t *nullce[MAX_PORTS];
for (int i=0;i<MAX_PORTS;i++) {
@ -264,19 +269,22 @@ int main(int argc, char **argv) {
chest_dl_estimate(&chest, sf_symbols, nullce, ue_sync_get_sfidx(&ue_sync));
rssi = VEC_CMA(chest_dl_get_rssi(&chest),rssi,nframes);
rsrq = VEC_CMA(chest_dl_get_rsrq(&chest),rsrq,nframes);
rssi = VEC_CMA(vec_avg_power_cf(sf_buffer,SF_LEN(lte_symbol_sz(cell.nof_prb))),rssi,nframes);
rssi_utra = VEC_CMA(chest_dl_get_rssi(&chest),rssi_utra,nframes);
rsrq = VEC_EMA(chest_dl_get_rsrq(&chest),rsrq,0.001);
rsrp = VEC_CMA(chest_dl_get_rsrp(&chest),rsrp,nframes);
snr = VEC_CMA(chest_dl_get_snr(&chest),snr,nframes);
nframes++;
// Plot and Printf
if ((nframes%10) == 0) {
printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, RSSI: %+5.1f dBm, "
printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, RSSI: %5.1f dBm, RSSI/ref-symbol: %+5.1f dBm, "
"RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rssi*1000/4/cell.nof_prb/12/2)-prog_args.uhd_gain,
10*log10(rsrp*1000)-prog_args.uhd_gain,
10*log10(rssi*1000)-gain_offset,
10*log10(rssi_utra*1000)-gain_offset,
10*log10(rsrp*1000)-gain_offset,
10*log10(rsrq), 10*log10(snr));
}
break;

View File

@ -253,8 +253,8 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
}
nof_trials++;
snr = VEC_CMA(chest_dl_get_snr(&ue_dl.chest), snr, nof_trials);
}
snr = VEC_EMA(chest_dl_get_snr(&ue_dl.chest), snr, 0.01);
}
}
if (ue_sync_get_sfidx(&ue_sync) == 9) {

View File

@ -69,7 +69,7 @@ typedef struct {
interp_linvec_t interp_linvec;
interp_lin_t interp_lin;
float rssi;
float rssi[MAX_PORTS];
float rsrp[MAX_PORTS];
float noise_estimate[MAX_PORTS];
} chest_dl_t;

View File

@ -36,10 +36,10 @@
typedef _Complex float cf_t;
// Cumulative moving average
#define VEC_CMA(data, average, n) ((data) + ((data) - (average)) / ((n)+1))
#define VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n)+1))
// Exponential moving average
#define VEC_EMA(data, average, alpha) ((alpha)*(data)+(1-alpha)*(average))
#define VEC_EMA(data, average, alpha) (average)==0?(data):((alpha)*(data)+(1-alpha)*(average))
/** Return the sum of all the elements */
LIBLTE_API int vec_acc_ii(int *x, uint32_t len);

View File

@ -280,26 +280,21 @@ static void interpolate_pilots(chest_dl_t *q, cf_t *ce, uint32_t port_id)
}
}
float chest_dl_rssi(lte_cell_t cell, cf_t *input) {
float rssi = 0;
uint32_t l, p;
uint32_t loop_ports = cell.nof_ports>2?2:1;
float chest_dl_rssi(chest_dl_t *q, cf_t *input, uint32_t port_id) {
uint32_t l;
for (p=0;p<loop_ports;p++) {
uint32_t nsymbols = refsignal_cs_nof_symbols(2*p);
for (l=0;l<nsymbols;l++) {
cf_t *tmp = &input[refsignal_nsymbol(l,cell.cp, 2*p) * cell.nof_prb * RE_X_RB];
rssi += crealf(vec_dot_prod_conj_ccc(tmp, tmp, cell.nof_prb * RE_X_RB));
}
}
return rssi;
float rssi = 0;
uint32_t nsymbols = refsignal_cs_nof_symbols(port_id);
for (l=0;l<nsymbols;l++) {
cf_t *tmp = &input[refsignal_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * RE_X_RB];
rssi += vec_dot_prod_conj_ccc(tmp,tmp,q->cell.nof_prb * RE_X_RB);
}
return rssi/nsymbols;
}
float chest_dl_rsrp(chest_dl_t *q, uint32_t port_id) {
return crealf(vec_dot_prod_conj_ccc(q->pilot_estimates_average[port_id],
q->pilot_estimates_average[port_id],
REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)))
/ REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
return vec_avg_power_cf(q->pilot_recv_signal[port_id],
REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
}
int chest_dl_estimate_port(chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id)
@ -307,16 +302,23 @@ int chest_dl_estimate_port(chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx
/* Get references from the input signal */
refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal[port_id]);
/* Compute RSRP for the references in this port */
if (port_id == 0) {
q->rsrp[port_id] = chest_dl_rsrp(q, port_id);
}
/* compute rssi */
if (port_id == 0) {
q->rssi[port_id] = chest_dl_rssi(q, input, port_id);
}
/* Use the known CSR signal to compute Least-squares estimates */
vec_prod_conj_ccc(q->pilot_recv_signal[port_id], q->csr_signal.pilots[port_id/2][sf_idx],
q->pilot_estimates[port_id], REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
/* Average pilot estimates */
average_pilots(q, port_id);
/* Compute RSRP for the references in this port */
q->rsrp[port_id] = chest_dl_rsrp(q, port_id);
/* Interpolate to create channel estimates for all resource grid */
if (ce != NULL) {
interpolate_pilots(q, ce, port_id);
@ -334,8 +336,6 @@ int chest_dl_estimate(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t
for (port_id=0;port_id<q->cell.nof_ports;port_id++) {
chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id);
}
/* compute rssi */
q->rssi = chest_dl_rssi(q->cell, input);
return LIBLTE_SUCCESS;
}
@ -346,21 +346,28 @@ float chest_dl_get_noise_estimate(chest_dl_t *q) {
float chest_dl_get_snr(chest_dl_t *q) {
float noise = chest_dl_get_noise_estimate(q);
if (noise) {
return chest_dl_get_rssi(q)/(noise*2*q->cell.nof_ports*lte_symbol_sz(q->cell.nof_prb));
return chest_dl_get_rssi(q)/(noise);//*2*q->cell.nof_ports*lte_symbol_sz(q->cell.nof_prb));
} else {
return 0.0;
}
}
float chest_dl_get_rssi(chest_dl_t *q) {
return q->rssi;
return 4*q->rssi[0]/q->cell.nof_prb/RE_X_RB;
}
/* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb is the average power per PRB
* q->rsrp[0] is the average power of RE containing references only (for port 0).
*/
float chest_dl_get_rsrq(chest_dl_t *q) {
return (4*q->cell.nof_ports*q->cell.nof_prb) * chest_dl_get_rsrp(q) / q->rssi;
return q->cell.nof_prb*q->rsrp[0] / q->rssi[0];
}
float chest_dl_get_rsrp(chest_dl_t *q) {
return vec_acc_ff(q->rsrp, q->cell.nof_ports)/q->cell.nof_ports;
// return linear average from port 0 only
return q->rsrp[0];
// return linear average from all ports
//return vec_acc_ff(q->rsrp, q->cell.nof_ports)/q->cell.nof_ports;
}

View File

@ -34,6 +34,9 @@
#include "liblte/phy/sync/sync.h"
#include "liblte/phy/utils/vector.h"
#define MEANENERGY_EMA_ALPHA 0.5
#define MEANPEAK_EMA_ALPHA 0.2
static bool fft_size_isvalid(uint32_t fft_size) {
if (fft_size >= FFT_SIZE_MIN && fft_size <= FFT_SIZE_MAX && (fft_size%64) == 0) {
@ -55,7 +58,8 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
bzero(q, sizeof(sync_t));
q->detect_cp = true;
q->normalize_en = true;
q->mean_energy = 1.0;
q->mean_energy = 0.0;
q->mean_peak_value = 0.0;
q->sss_en = true;
q->N_id_2 = 1000;
q->N_id_1 = 1000;
@ -261,22 +265,26 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
return LIBLTE_ERROR;
}
if (q->normalize_en &&
peak_pos < q->frame_size &&
peak_pos + find_offset >= q->fft_size )
{
/* Compute the energy of the received PSS sequence to normalize */
energy = sqrtf(vec_avg_power_cf(&input[find_offset+peak_pos-q->fft_size], q->fft_size));
q->mean_energy = VEC_CMA(energy, q->mean_energy, q->frame_cnt);
q->mean_energy = VEC_EMA(energy, q->mean_energy, MEANENERGY_EMA_ALPHA);
} else {
if (q->mean_energy == 0.0) {
q->mean_energy = 1.0;
energy = 1.0;
} else {
energy = q->mean_energy;
}
energy = q->mean_energy;
}
/* Normalize and compute mean peak value */
q->peak_value = peak_unnormalized/energy;
q->mean_peak_value = VEC_CMA(q->peak_value, q->mean_peak_value, q->frame_cnt);
if (q->mean_energy) {
q->peak_value = peak_unnormalized/q->mean_energy;
} else {
q->peak_value = peak_unnormalized/energy;
}
q->mean_peak_value = VEC_EMA(q->peak_value, q->mean_peak_value, MEANPEAK_EMA_ALPHA);
q->frame_cnt++;
if (peak_position) {
@ -284,7 +292,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
}
/* If peak is over threshold, compute CFO and SSS */
if (q->peak_value >= q->threshold) {
if (q->peak_value >= q->threshold) {
// Set an invalid N_id_1 indicating SSS is yet to be detected
q->N_id_1 = 1000;
@ -296,9 +304,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
}
}
// Make sure we have enough space to estimate CFO
if (peak_pos < q->frame_size &&
peak_pos + find_offset >= q->fft_size)
{
if (peak_pos + find_offset >= q->fft_size) {
q->cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]);
} else {
INFO("No space for CFO computation. Frame starts at \n",peak_pos);
@ -309,8 +315,9 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
ret = 0;
}
INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f/%.2f=%.2f threshold=%.2f sf_idx=%d offset=%d\n",
ret, q->N_id_2, peak_pos, peak_unnormalized,energy,q->peak_value, q->threshold, q->sf_idx, find_offset);
INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f/%.2f=%.2f mean_energy=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n",
ret, q->N_id_2, peak_pos, peak_unnormalized*1000,energy*1000,q->peak_value, q->mean_energy*1000,
q->threshold, q->sf_idx, 15*q->cfo);
} else if (lte_N_id_2_isvalid(q->N_id_2)) {
fprintf(stderr, "Must call sync_set_N_id_2() first!\n");

View File

@ -46,10 +46,12 @@ cf_t dummy[MAX_TIME_OFFSET];
#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define FIND_THRESHOLD 1.4
#define TRACK_THRESHOLD 0.7
#define FIND_THRESHOLD 1.5
#define TRACK_THRESHOLD 0.8
#define TRACK_MAX_LOST 10
#define CFO_EMA_ALPHA 0.01
int ue_sync_init(ue_sync_t *q,
lte_cell_t cell,
@ -145,7 +147,7 @@ float ue_sync_get_cfo(ue_sync_t *q) {
}
float ue_sync_get_sfo(ue_sync_t *q) {
return 1000*q->mean_time_offset;
return 5000*q->mean_time_offset;
}
void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
@ -209,9 +211,9 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
}
/* compute cumulative moving average CFO */
q->cur_cfo = VEC_CMA(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt);
q->cur_cfo = VEC_EMA(sync_get_cfo(&q->strack), q->cur_cfo, CFO_EMA_ALPHA);
/* compute cumulative moving average time offset */
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt);
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt);
q->peak_idx = CURRENT_SFLEN/2 + q->time_offset;
q->frame_ok_cnt++;
@ -356,8 +358,8 @@ void ue_sync_reset(ue_sync_t *q) {
q->frame_ok_cnt = 0;
q->frame_no_cnt = 0;
q->frame_total_cnt = 0;
q->cur_cfo = 0;
q->mean_time_offset = 0;
q->cur_cfo = 0.0;
q->mean_time_offset = 0.0;
q->time_offset = 0;
#ifdef MEASURE_EXEC_TIME
q->mean_exec_time = 0;

View File

@ -475,12 +475,7 @@ float vec_dot_prod_fff(float *x, float *y, uint32_t len) {
float vec_avg_power_cf(cf_t *x, uint32_t len) {
int j;
float power = 0;
for (j=0;j<len;j++) {
power += crealf(x[j]*conjf(x[j]));
}
return power / len;
return crealf(vec_dot_prod_conj_ccc(x,x,len)) / len;
}
void vec_abs_cf(cf_t *x, float *abs, uint32_t len) {