Improvements in prach detection

This commit is contained in:
Ismael Gomez 2016-07-27 16:44:14 +02:00
parent 9618135423
commit cc00b172b5
13 changed files with 124 additions and 61 deletions

View File

@ -1,22 +1,23 @@
%% PRACH Detection Conformance Test
clear
%clear
d=18;%linspace(4,14,6);
d=50;%linspace(4,14,6);
pDetection2 = zeros(2,length(d));
for dd=1:length(d)
detect_factor=d(dd);
numSubframes = 75; % Number of subframes frames to simulate at each SNR
SNRdB = linspace(-14,10,8); % SNR points to simulate
foffset = 300.0; % Frequency offset in Hertz
add_fading=true;
numSubframes = 1; % Number of subframes frames to simulate at each SNR
SNRdB = 10;%linspace(-14,10,8); % SNR points to simulate
foffset = 0.0; % Frequency offset in Hertz
delay=0;
add_fading=false;
addpath('../../build/srslte/lib/phch/test')
%% UE Configuration
% User Equipment (UE) settings are specified in the structure |ue|.
ue.NULRB = 100; % 6 Resource Blocks
ue.NULRB = 15; % 6 Resource Blocks
ue.DuplexMode = 'FDD'; % Frequency Division Duplexing (FDD)
ue.CyclicPrefixUL = 'Normal'; % Normal cyclic prefix length
ue.NTxAnts = 1; % Number of transmission antennas
@ -25,8 +26,7 @@ ue.NTxAnts = 1; % Number of transmission antennas
prach.Format = 0; % PRACH format: TS36.104, Table 8.4.2.1-1
prach.HighSpeed = 0; % Normal mode: TS36.104, Table 8.4.2.1-1
prach.FreqOffset = 0; % Default frequency location
prach.FreqOffset = 4; % Default frequency location
info = ltePRACHInfo(ue, prach); % PRACH information
%% Propagation Channel Configuration
@ -67,9 +67,9 @@ for nSNR = 1:length(SNRdB)
% Loop for each subframe
for nsf = 1:numSubframes
prach.SeqIdx = randi(838,1,1)-1; % Logical sequence index: TS36.141, Table A.6-1
prach.CyclicShiftIdx = randi(16,1,1)-1; % Cyclic shift index: TS36.141, Table A.6-1
prach.PreambleIdx = randi(64,1,1)-1; % Preamble index: TS36.141, Table A.6-1
prach.SeqIdx = 0;%randi(838,1,1)-1; % Logical sequence index: TS36.141, Table A.6-1
prach.CyclicShiftIdx = 11;%randi(16,1,1)-1; % Cyclic shift index: TS36.141, Table A.6-1
prach.PreambleIdx = 1;%randi(64,1,1)-1; % Preamble index: TS36.141, Table A.6-1
info = ltePRACHInfo(ue, prach); % PRACH information
% PRACH transmission
@ -77,8 +77,8 @@ for nSNR = 1:length(SNRdB)
ue.NFrame = fix((nsf-1)/10);
% Set PRACH timing offset in us as per TS36.141, Figure 8.4.1.4.2-2
prach.TimingOffset = info.BaseOffset + ue.NSubframe/10.0;
% prach.TimingOffset = 0;
%prach.TimingOffset = info.BaseOffset + ue.NSubframe/10.0;
prach.TimingOffset = 0;
% Generate transmit wave
[txwave,prachinfo] = ltePRACH(ue, prach);
@ -92,23 +92,30 @@ for nSNR = 1:length(SNRdB)
rxwave = txwave;
end
% Add noise
noise = N*complex(randn(size(rxwave)), randn(size(rxwave)));
rxwave = rxwave + noise;
%noise = N*complex(randn(size(rxwave)), randn(size(rxwave)));
%rxwave = rxwave + noise;
% Remove the implementation delay of the channel modeling
if (add_fading)
rxwave = rxwave((fadinginfo.ChannelFilterDelay + 1):end, :);
end
rxwave=x;
% rxwave=[zeros(delay,1); txwave(1:end-delay)];
% Apply frequency offset
t = ((0:size(rxwave, 1)-1)/chcfg.SamplingRate).';
rxwave = rxwave .* repmat(exp(1i*2*pi*foffset*t), ...
1, size(rxwave, 2));
% PRACH detection for all cell preamble indices
[detected, offsets] = ltePRACHDetect(ue, prach, rxwave, (0:63).');
[detected_srs, offsets_srs] = srslte_prach_detect(ue, prach, rxwave, detect_factor);
[detected_srs, offsets_srs, corrout] = srslte_prach_detect(ue, prach, rxwave, detect_factor);
disp(detected)
disp(detected_srs)
disp(offsets_srs*1e6)
% Test for preamble detection
if (length(detected)==1)
@ -144,7 +151,7 @@ for nSNR = 1:length(SNRdB)
% Calculate timing estimation error. The true offset is
% PRACH offset plus channel delay
trueOffset = prach.TimingOffset/1e6 + 310e-9;
measuredOffset = offsets_srs(1)/1e6;
measuredOffset = offsets_srs(1);
timingerror = abs(measuredOffset-trueOffset);
% Test for acceptable timing error
@ -189,3 +196,4 @@ else
fprintf('Pdet=%.4f%%, Pdet_srs=%.4f%%\n',pDetection(1,nSNR),pDetection(2,nSNR))
end
plot(corrout)

View File

@ -500,7 +500,6 @@ int main(int argc, char **argv) {
decode_pdsch = false;
}
}
if (decode_pdsch) {
INFO("Attempting DL decode SFN=%d\n", sfn);
if (prog_args.rnti != SRSLTE_SIRNTI) {
@ -509,7 +508,6 @@ int main(int argc, char **argv) {
// RV for SIB1 is predefined
uint32_t k = (sfn/2)%4;
uint32_t rv = ((uint32_t) ceilf((float)1.5*k))%4;
n = srslte_ue_dl_decode_rnti_rv(&ue_dl, &sf_buffer[prog_args.time_offset], data,
srslte_ue_sync_get_sfidx(&ue_sync),
SRSLTE_SIRNTI, rv);

View File

@ -86,7 +86,6 @@ typedef struct SRSLTE_API {
cf_t pss_signal[SRSLTE_PSS_LEN];
float sss_signal0[SRSLTE_SSS_LEN];
float sss_signal5[SRSLTE_SSS_LEN];
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
uint32_t nof_rnti;

View File

@ -122,7 +122,8 @@ SRSLTE_API int srslte_enb_ul_detect_prach(srslte_enb_ul_t *q,
uint32_t freq_offset,
cf_t *signal,
uint32_t *indices,
uint32_t *offsets);
float *offsets,
float *peak2avg);
#endif

View File

@ -64,6 +64,7 @@ typedef struct SRSLTE_API {
uint32_t N_zc; // PRACH sequence length
uint32_t N_cs; // Cyclic shift size
uint32_t N_seq; // Preamble length
float T_seq; // Preamble length in seconds
uint32_t N_cp; // Cyclic prefix length
// Generated tables
@ -153,7 +154,8 @@ SRSLTE_API int srslte_prach_detect_offset(srslte_prach_t *p,
cf_t *signal,
uint32_t sig_len,
uint32_t *indices,
uint32_t *offsets,
float *t_offsets,
float *peak_to_avg,
uint32_t *ind_len);
SRSLTE_API void srslte_prach_set_detect_factor(srslte_prach_t *p,

View File

@ -175,9 +175,11 @@ void srslte_enb_dl_put_refs(srslte_enb_dl_t *q, uint32_t sf_idx)
void srslte_enb_dl_put_mib(srslte_enb_dl_t *q, uint32_t tti)
{
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
if ((tti%10) == 0) {
srslte_pbch_mib_pack(&q->cell, tti/10, q->bch_payload);
srslte_pbch_encode(&q->pbch, q->bch_payload, q->slot1_symbols, ((tti/10)%4));
srslte_pbch_mib_pack(&q->cell, tti/10, bch_payload);
srslte_pbch_encode(&q->pbch, bch_payload, q->slot1_symbols, ((tti/10)%4));
}
}
@ -237,13 +239,16 @@ int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant,
if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) {
rnti_is_user = false;
}
//srslte_ra_pdsch_fprint(stdout, grant, q->cell.nof_prb);
srslte_dci_msg_pack_pdsch(grant, &dci_msg, format, q->cell.nof_prb, rnti_is_user);
//srslte_vec_fprint_hex(stdout, dci_msg.data, dci_msg.nof_bits);
if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
return SRSLTE_ERROR;
}
/* printf("format: %s, sf_idx=%d, rnti=%d, location=%d,%d, cfi=%d\n",
srslte_dci_format_string(format), sf_idx, rnti, location.L, location.ncce, q->cfi);
srslte_ra_pdsch_fprint(stdout, grant, q->cell.nof_prb);
srslte_vec_fprint_hex(stdout, dci_msg.data, dci_msg.nof_bits);
*/
return SRSLTE_SUCCESS;
}

View File

@ -83,6 +83,8 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell,
fprintf(stderr, "Error initiating PRACH\n");
goto clean_exit;
}
srslte_prach_set_detect_factor(&q->prach, 60);
if (srslte_chest_ul_init(&q->chest, cell)) {
fprintf(stderr, "Error initiating channel estimator\n");
@ -177,18 +179,20 @@ int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srs
int srslte_enb_ul_detect_prach(srslte_enb_ul_t *q, uint32_t tti,
uint32_t freq_offset, cf_t *signal,
uint32_t *indices, uint32_t *offsets)
uint32_t *indices, float *offsets, float *peak2avg)
{
uint32_t nof_detected_prach = 0;
// consider the number of subframes the transmission must be anticipated
if (srslte_prach_tti_opportunity(&q->prach, tti, -1))
{
if (srslte_prach_detect_offset(&q->prach,
freq_offset,
&signal[q->prach.N_cp],
SRSLTE_SF_LEN_PRB(q->cell.nof_prb),
indices,
offsets,
peak2avg,
&nof_detected_prach))
{
fprintf(stderr, "Error detecting PRACH\n");

View File

@ -50,7 +50,7 @@ int srslte_mod_modulate(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, u
}
return j;
}
void mod_bpsk_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symbols, uint32_t nbits) {
uint8_t mask_bpsk[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
uint8_t shift_bpsk[8] = {7, 6, 5, 4, 3, 2, 1, 0};

View File

@ -292,8 +292,10 @@ void srslte_pbch_mib_unpack(uint8_t *msg, srslte_cell_t *cell, uint32_t *sfn) {
/** Unpacks MIB from PBCH message.
* msg buffer must be 24 byte length at least
*/
void srslte_pbch_mib_pack(srslte_cell_t *cell, uint32_t sfn, uint8_t *msg) {
void srslte_pbch_mib_pack(srslte_cell_t *cell, uint32_t sfn, uint8_t *payload) {
int bw, phich_res = 0;
uint8_t *msg = payload;
bzero(msg, 24);
@ -325,6 +327,7 @@ void srslte_pbch_mib_pack(srslte_cell_t *cell, uint32_t sfn, uint8_t *msg) {
}
srslte_bit_unpack(phich_res, &msg, 2);
srslte_bit_unpack(sfn >> 2, &msg, 8);
}
void srslte_pbch_decode_reset(srslte_pbch_t *q) {

View File

@ -32,10 +32,10 @@
#include "srslte/utils/debug.h"
#include "srslte/utils/vector.h"
float save_corr[4096];
//PRACH detection threshold is PRACH_DETECT_FACTOR*average
#define PRACH_DETECT_FACTOR 18
#define CFO_REPLICA_FACTOR 0.3
#define N_SEQS 64 // Number of prach sequences available
#define N_RB_SC 12 // Number of subcarriers per resource block
@ -440,8 +440,9 @@ int srslte_prach_init(srslte_prach_t *p,
srslte_dft_plan_set_norm(p->fft, false);
p->N_seq = prach_Tseq[p->f]*p->N_ifft_ul/2048;
p->N_cp = prach_Tcp[p->f]*p->N_ifft_ul/2048;
p->N_cp = prach_Tcp[p->f]*p->N_ifft_ul/2048;
p->T_seq = prach_Tseq[p->f]*SRSLTE_LTE_TS;
ret = SRSLTE_SUCCESS;
} else {
fprintf(stderr, "Invalid parameters\n");
@ -506,7 +507,7 @@ int srslte_prach_detect(srslte_prach_t *p,
uint32_t *indices,
uint32_t *n_indices)
{
return srslte_prach_detect_offset(p, freq_offset, signal, sig_len, indices, NULL, n_indices);
return srslte_prach_detect_offset(p, freq_offset, signal, sig_len, indices, NULL, NULL, n_indices);
}
int srslte_prach_detect_offset(srslte_prach_t *p,
@ -514,7 +515,8 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
cf_t *signal,
uint32_t sig_len,
uint32_t *indices,
uint32_t *offsets,
float *t_offsets,
float *peak_to_avg,
uint32_t *n_indices)
{
int ret = SRSLTE_ERROR;
@ -525,7 +527,7 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
{
if(sig_len < p->N_ifft_prach){
fprintf(stderr, "srslte_prach_detect: Signal is not of length %d", p->N_ifft_prach);
fprintf(stderr, "srslte_prach_detect: Signal length is %d and should be %d\n", sig_len, p->N_ifft_prach);
return SRSLTE_ERROR_INVALID_INPUTS;
}
@ -562,7 +564,6 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
uint32_t n_wins = p->N_zc/winsize;
float max_peak = 0;
for(int j=0;j<n_wins;j++) {
uint32_t start = (p->N_zc-(j*p->N_cs))%p->N_zc;
uint32_t end = start+winsize;
@ -583,12 +584,20 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
}
if (max_peak > p->detect_factor*corr_ave) {
for (int j=0;j<n_wins;j++) {
if(p->peak_values[j] > p->detect_factor*corr_ave &&
p->peak_values[j] >= CFO_REPLICA_FACTOR*max_peak)
if(p->peak_values[j] > p->detect_factor*corr_ave)
{
indices[*n_indices] = (i*n_wins)+j;
if (offsets) {
offsets[*n_indices] = p->peak_offsets[j];
printf("ncs=%d, nzc=%d, nwins=%d, Nroot=%d, i=%d, j=%d, start=%d, peak_value=%f, peak_offset=%d, tseq=%f\n",
p->N_cs, p->N_zc, n_wins, p->N_roots, i, j, (p->N_zc-(j*p->N_cs))%p->N_zc, p->peak_values[j],
p->peak_offsets[j], p->T_seq*1e6);
memcpy(save_corr, p->corr, p->N_zc*sizeof(float));
if (indices) {
indices[*n_indices] = (i*n_wins)+j;
}
if (peak_to_avg) {
peak_to_avg[*n_indices] = p->peak_values[j]/corr_ave;
}
if (t_offsets) {
t_offsets[*n_indices] = (float) p->peak_offsets[j]*p->T_seq/p->N_zc;
}
(*n_indices)++;
}

View File

@ -29,6 +29,8 @@
#include "srslte/srslte.h"
#include "srslte/mex/mexutils.h"
extern float save_corr[4096];
/** MEX function to be called from MATLAB to test the channel estimator
*/
@ -85,7 +87,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexutils_read_uint32_struct(PRACHCFG, "FreqOffset", &frequency_offset);
srslte_prach_t prach;
if (srslte_prach_init(&prach, N_ifft_ul, preamble_format, root_seq_idx, high_speed_flag, zero_corr_zone)) {
if (srslte_prach_init(&prach, N_ifft_ul, preamble_format*16, root_seq_idx, high_speed_flag, zero_corr_zone)) {
mexErrMsgTxt("Error initiating PRACH\n");
return;
}
@ -94,7 +96,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
int nof_samples = mexutils_read_cf(INPUT, &input_signal);
uint32_t preambles[64];
uint32_t offsets[64];
float offsets[64];
uint32_t nof_detected = 0;
if (nrhs > NOF_INPUTS) {
@ -102,7 +104,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_prach_set_detect_factor(&prach, factor);
}
if (srslte_prach_detect_offset(&prach, frequency_offset, &input_signal[prach.N_cp], nof_samples, preambles, offsets, &nof_detected)) {
if (srslte_prach_detect_offset(&prach, frequency_offset, &input_signal[prach.N_cp], nof_samples, preambles, offsets, NULL, &nof_detected)) {
mexErrMsgTxt("Error detecting PRACH\n");
return;
}
@ -111,7 +113,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexutils_write_int((int*) preambles, &plhs[0], nof_detected, 1);
}
if (nlhs >= 2) {
mexutils_write_int((int*) offsets, &plhs[1], nof_detected, 1);
mexutils_write_f(offsets, &plhs[1], nof_detected, 1);
}
if (nlhs >= 3) {
mexutils_write_f(save_corr, &plhs[2], prach.N_zc, 1);
}
free(input_signal);

View File

@ -82,7 +82,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexutils_read_uint32_struct(PRACHCFG, "FreqOffset", &frequency_offset);
srslte_prach_t prach;
if (srslte_prach_init(&prach, N_ifft_ul, preamble_format, root_seq_idx, high_speed_flag, zero_corr_zone)) {
if (srslte_prach_init(&prach, N_ifft_ul, preamble_format*16, root_seq_idx, high_speed_flag, zero_corr_zone)) {
mexErrMsgTxt("Error initiating PRACH\n");
return;
}

View File

@ -44,12 +44,13 @@ uint32_t preamble_format = 0;
uint32_t root_seq_idx = 0;
uint32_t seq_idx = 0;
uint32_t frequency_offset = 0;
uint32_t zero_corr_zone = 0;
uint32_t zero_corr_zone = 11;
uint32_t timeadv = 0;
uint32_t nof_frames = 20;
float uhd_gain=40, uhd_freq=2.4e9;
char *uhd_args="";
char *output_filename = NULL;
char *output_filename = "prach_rx";
void usage(char *prog) {
printf("Usage: %s \n", prog);
@ -58,15 +59,17 @@ void usage(char *prog) {
printf("\t-g UHD TX/RX gain [Default %.1f dB]\n", uhd_gain);
printf("\t-p Number of UL RB [Default %d]\n", nof_prb);
printf("\t-F Preamble format [Default %d]\n", preamble_format);
printf("\t-O Frequency offset [Default %d]\n", frequency_offset);
printf("\t-s sequence index [Default %d]\n", seq_idx);
printf("\t-r Root sequence index [Default %d]\n", root_seq_idx);
printf("\t-t Time advance (us) [Default %d]\n", timeadv);
printf("\t-z Zero correlation zone config [Default %d]\n", zero_corr_zone);
printf("\t-o Save transmitted PRACH in file [Default no]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "apfFgrsoz")) != -1) {
while ((opt = getopt(argc, argv, "apfFgrstoPOz")) != -1) {
switch (opt) {
case 'a':
uhd_args = argv[optind];
@ -80,6 +83,15 @@ void parse_args(int argc, char **argv) {
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'P':
preamble_format = atoi(argv[optind]);
break;
case 'O':
frequency_offset = atoi(argv[optind]);
break;
case 't':
timeadv = atoi(argv[optind]);
break;
case 'p':
nof_prb = atoi(argv[optind]);
if (!srslte_nofprb_isvalid(nof_prb)) {
@ -123,7 +135,8 @@ int main(int argc, char **argv) {
high_speed_flag,
zero_corr_zone);
uint32_t flen = srslte_sampling_freq_hz(nof_prb)/1000;
int srate = srslte_sampling_freq_hz(nof_prb);
uint32_t flen = srate/1000;
printf("Generating PRACH\n");
bzero(preamble, flen*sizeof(cf_t));
@ -133,7 +146,7 @@ int main(int argc, char **argv) {
preamble);
uint32_t prach_len = p->N_seq;
uint32_t prach_len = p->N_seq+p->N_cp;
srslte_vec_save_file("generated",preamble,prach_len*sizeof(cf_t));
@ -147,11 +160,27 @@ int main(int argc, char **argv) {
exit(-1);
}
printf("Subframe len: %d samples\n", flen);
printf("Set TX/RX rate: %.2f MHz\n", srslte_rf_set_rx_srate(&uhd, srslte_sampling_freq_hz(nof_prb)) / 1000000);
printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&uhd, uhd_gain));
printf("Set TX gain: %.1f dB\n", srslte_rf_set_tx_gain(&uhd, uhd_gain));
printf("Set TX/RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&uhd, uhd_freq) / 1000000);
srslte_rf_set_tx_srate(&uhd, srslte_sampling_freq_hz(nof_prb));
printf("Set RX gain: %.1f dB\n", uhd_gain);
printf("Set TX gain: %.1f dB\n", 20+uhd_gain);
printf("Set TX/RX freq: %.2f MHz\n", uhd_freq/ 1000000);
srslte_rf_set_rx_gain(&uhd, uhd_gain);
srslte_rf_set_tx_gain(&uhd, 10+uhd_gain);
srslte_rf_set_rx_freq(&uhd, uhd_freq);
srslte_rf_set_tx_freq(&uhd, uhd_freq);
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&uhd, 4*srate);
} else {
srslte_rf_set_master_clock_rate(&uhd, srate);
}
printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000);
float srate_rf = srslte_rf_set_rx_srate(&uhd, (double) srate);
if (srate_rf != srate) {
fprintf(stderr, "Could not set sampling rate\n");
exit(-1);
}
srslte_rf_set_tx_srate(&uhd, (double) srate);
sleep(1);
cf_t *zeros = calloc(sizeof(cf_t),flen);
@ -171,7 +200,7 @@ int main(int argc, char **argv) {
srslte_rf_recv_with_time(&uhd, &buffer[flen*nframe], flen, true, &tstamp.full_secs, &tstamp.frac_secs);
nframe++;
if (nframe==9 || nframe==8) {
srslte_timestamp_add(&tstamp, 0, 2e-3);
srslte_timestamp_add(&tstamp, 0, 2e-3-timeadv*1e-6);
if (nframe==8) {
srslte_rf_send_timed2(&uhd, zeros, flen, tstamp.full_secs, tstamp.frac_secs, true, false);
printf("Transmitting zeros\n");
@ -183,7 +212,7 @@ int main(int argc, char **argv) {
}
if (f) {
fwrite(&buffer[10*flen], flen*sizeof(cf_t), 1, f);
fwrite(buffer, 11*flen*sizeof(cf_t), 1, f);
}
if (f) {
fclose(f);