mirror of https://github.com/PentHertz/srsLTE.git
Improved UE measurements. Calibrated for gain 40 dB
This commit is contained in:
parent
632e841dbe
commit
445fc639e8
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue