mirror of https://github.com/pvnis/srsRAN_4G.git
Fixed PDSCH UE example. Added ue_dl and ue_sync modules. Fixed other minor bugs
parent
09243c7996
commit
7372d3a386
@ -0,0 +1,168 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UE_SYNC_
|
||||
#define UE_SYNC_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/sync/sync.h"
|
||||
#include "liblte/phy/sync/cfo.h"
|
||||
#include "liblte/phy/ch_estimation/chest.h"
|
||||
#include "liblte/phy/phch/pbch.h"
|
||||
#include "liblte/phy/common/fft.h"
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* This object automatically manages the cell association and
|
||||
* synchronization procedure. By default, it associates with the
|
||||
* CELL whose correlation peak to average ratio is the highest.
|
||||
*
|
||||
* TODO: Associate with arbitrary CELL ID
|
||||
*
|
||||
* The main function is ue_sync_get_buffer(), which returns a pointer
|
||||
* to the aligned subframe of samples (before FFT). This function
|
||||
* should be called regularly, returning every 1 ms. It reads from the
|
||||
* USRP, aligns the samples to the subframe and performs time/freq synch.
|
||||
*
|
||||
* The function returns 0 during the cell association procedure, which includes
|
||||
* PSS/SSS synchronization, MIB decoding from the PBCH and sampling frequency
|
||||
* adjustment (according to signal bandwidth) and resynchronization.
|
||||
*
|
||||
* The function returns 1 when the signal is correctly acquired and the
|
||||
* returned buffer is aligned with the subframe.
|
||||
*
|
||||
*
|
||||
*************************************************************/
|
||||
|
||||
typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t;
|
||||
|
||||
#define SYNC_PBCH_NOF_PRB 6
|
||||
#define SYNC_PBCH_NOF_PORTS 2
|
||||
|
||||
#define TRACK_MAX_LOST 10
|
||||
#define PAR_THRESHOLD_FIND 20
|
||||
|
||||
#define NOF_MIB_DECODES 10
|
||||
|
||||
#define MEASURE_EXEC_TIME
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
sync_t s;
|
||||
|
||||
void *stream;
|
||||
double (*set_rate_callback)(void*, double);
|
||||
int (*recv_callback)(void*, void*, uint32_t);
|
||||
|
||||
ue_sync_state_t state;
|
||||
|
||||
cf_t *input_buffer;
|
||||
cf_t *sf_symbols;
|
||||
cf_t *ce[SYNC_PBCH_NOF_PORTS];
|
||||
|
||||
/* These count half frames (5ms) */
|
||||
uint64_t frame_ok_cnt;
|
||||
uint32_t frame_no_cnt;
|
||||
uint32_t frame_total_cnt;
|
||||
|
||||
/* this is the system frame number (SFN) */
|
||||
uint32_t frame_number;
|
||||
|
||||
lte_cell_t cell;
|
||||
uint32_t sf_idx;
|
||||
|
||||
cfo_t cfocorr;
|
||||
float cur_cfo;
|
||||
|
||||
/* Variables for PBCH decoding */
|
||||
pbch_mib_t mib;
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
pbch_t pbch;
|
||||
bool pbch_initialized;
|
||||
uint32_t pbch_decoded;
|
||||
bool pbch_decode_always;
|
||||
bool pbch_decoder_enabled;
|
||||
uint32_t pbch_last_trial;
|
||||
|
||||
bool decode_sss_on_track;
|
||||
|
||||
uint32_t peak_idx;
|
||||
int time_offset;
|
||||
float mean_time_offset;
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
float mean_exec_time;
|
||||
#endif
|
||||
} ue_sync_t;
|
||||
|
||||
|
||||
LIBLTE_API int ue_sync_init(ue_sync_t *q,
|
||||
double (set_rate_callback)(void*, double),
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
|
||||
LIBLTE_API void ue_sync_free(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q,
|
||||
cf_t **sf_symbols);
|
||||
|
||||
|
||||
LIBLTE_API void ue_sync_reset(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled);
|
||||
|
||||
LIBLTE_API void ue_sync_pbch_enable(ue_sync_t *q, bool enabled);
|
||||
|
||||
LIBLTE_API void ue_sync_pbch_always(ue_sync_t *q, bool enabled);
|
||||
|
||||
LIBLTE_API void ue_sync_set_threshold(ue_sync_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API uint32_t ue_sync_get_peak_idx(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API lte_cell_t ue_sync_get_cell(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API pbch_mib_t ue_sync_get_mib(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API bool ue_sync_is_mib_decoded(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SYNC_FRAME_
|
||||
|
@ -1,111 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SYNC_FRAME_
|
||||
#define SYNC_FRAME_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/sync/sync.h"
|
||||
#include "liblte/phy/sync/cfo.h"
|
||||
|
||||
/**
|
||||
*
|
||||
* Uses sync object to automatically manage the FIND and TRACKING states.
|
||||
* It is suposed to work on a subframe basis. The input signal must be sampled at
|
||||
* a frequency integer multiple of 1.92 MHz. The signal is internally downsampled
|
||||
* and fed to the sync object.
|
||||
*
|
||||
* This object also deals with frame alignment and CFO correction, returning an
|
||||
* output signal aligned both in time and frequency.
|
||||
*/
|
||||
|
||||
enum sync_frame_state { SF_FIND, SF_TRACK };
|
||||
|
||||
#define SYNC_SF_LEN 1920 // 1ms at 1.92 MHz
|
||||
|
||||
#define TRACK_MAX_LOST 10
|
||||
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
sync_t s;
|
||||
enum sync_frame_state state;
|
||||
uint32_t downsampling;
|
||||
resample_arb_t resample;
|
||||
unsigned long frame_cnt;
|
||||
bool fb_wp;
|
||||
uint32_t frame_size;
|
||||
cf_t *input_buffer;
|
||||
cf_t *input_downsampled;
|
||||
cfo_t cfocorr;
|
||||
float cur_cfo;
|
||||
uint32_t peak_idx;
|
||||
uint32_t cell_id;
|
||||
float timeoffset;
|
||||
uint32_t last_found;
|
||||
uint32_t sf_idx;
|
||||
}sync_frame_t;
|
||||
|
||||
|
||||
/* Initializes the automatic tracker, setting the downsampling ratio for the input signal.
|
||||
* downsampling is the ratio of the provided signal sampling frequency to 1.92 Mhz. E.g. if input is sampled at 3.84 Mhz,
|
||||
* downsampling should be 2.
|
||||
*/
|
||||
LIBLTE_API int sync_frame_init(sync_frame_t *q,
|
||||
uint32_t downsampling);
|
||||
|
||||
LIBLTE_API void sync_frame_free(sync_frame_t *q);
|
||||
|
||||
LIBLTE_API void sync_frame_set_threshold(sync_frame_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API uint32_t sync_frame_cell_id(sync_frame_t *q);
|
||||
|
||||
LIBLTE_API uint32_t sync_frame_sfidx(sync_frame_t *q);
|
||||
|
||||
/* Automatically time/freq synchronizes the input signal. Returns 1 if the signal is synched and locked,
|
||||
* and fills the output buffer with the time and frequency aligned version of the signal.
|
||||
* If 0 is returned, the PSS was not found. -1 is returned in case of error.
|
||||
*
|
||||
* The provided signal can be sampled at an integer multiple of 1.92 Mhz.
|
||||
* The sampling ratio is provided when calling the sync_auto_reset() function.
|
||||
*
|
||||
* The buffer input must have subframe_size samples (used in sync_init)
|
||||
*/
|
||||
LIBLTE_API int sync_frame_push(sync_frame_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output);
|
||||
|
||||
/* Resets the automatic tracker */
|
||||
LIBLTE_API void sync_frame_reset(sync_frame_t *q);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SYNC_FRAME_
|
||||
|
@ -0,0 +1,555 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "liblte/phy/phch/ue_sync.h"
|
||||
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
#define MAX_TIME_OFFSET 128
|
||||
cf_t dummy[MAX_TIME_OFFSET];
|
||||
|
||||
#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1))
|
||||
|
||||
#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb)
|
||||
#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp)
|
||||
|
||||
#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 MAXIMUM_SFLEN SF_LEN(2048, CPNORM)
|
||||
#define MAXIMUM_SFLEN_RE SF_LEN_RE(110, CPNORM)
|
||||
|
||||
static int mib_decoder_initialize(ue_sync_t *q);
|
||||
static void mib_decoder_free(ue_sync_t *q);
|
||||
|
||||
int ue_sync_init(ue_sync_t *q,
|
||||
double (set_rate_callback)(void*, double),
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
stream_handler != NULL)
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
bzero(q, sizeof(ue_sync_t));
|
||||
|
||||
ue_sync_reset(q);
|
||||
|
||||
q->cell.nof_prb = SYNC_PBCH_NOF_PRB;
|
||||
q->cell.nof_ports = SYNC_PBCH_NOF_PORTS;
|
||||
q->cell.id = 0;
|
||||
q->cell.cp = CPNORM;
|
||||
|
||||
q->pbch_decoded = false;
|
||||
q->pbch_initialized = false;
|
||||
q->pbch_decoder_enabled = true;
|
||||
q->pbch_decode_always = false;
|
||||
q->decode_sss_on_track = false;
|
||||
|
||||
q->stream = stream_handler;
|
||||
q->recv_callback = recv_callback;
|
||||
q->set_rate_callback = set_rate_callback;
|
||||
|
||||
INFO("Setting sampling frequency 1.92 MHz\n",0);
|
||||
q->set_rate_callback(q->stream, 1920000.0);
|
||||
|
||||
if(sync_init(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
sync_pss_det_peak_to_avg(&q->s);
|
||||
|
||||
if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->input_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t));
|
||||
if (!q->input_buffer) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->sf_symbols = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t));
|
||||
if (!q->sf_symbols) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
for (int i=0;i<SYNC_PBCH_NOF_PORTS;i++) {
|
||||
q->ce[i] = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t));
|
||||
if (!q->ce[i]) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
|
||||
//float th = PAR_THRESHOLD_FIND * (1+(float) CURRENT_FFTSIZE/128/10);
|
||||
sync_set_threshold(&q->s, PAR_THRESHOLD_FIND, PAR_THRESHOLD_FIND/4);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
ue_sync_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_sync_free(ue_sync_t *q) {
|
||||
if (q->input_buffer) {
|
||||
free(q->input_buffer);
|
||||
}
|
||||
if (q->sf_symbols) {
|
||||
free(q->sf_symbols);
|
||||
}
|
||||
for (int i=0;i<SYNC_PBCH_NOF_PORTS;i++) {
|
||||
if (q->ce[i]) {
|
||||
free(q->ce[i]);
|
||||
}
|
||||
}
|
||||
mib_decoder_free(q);
|
||||
cfo_free(&q->cfocorr);
|
||||
sync_free(&q->s);
|
||||
}
|
||||
|
||||
void ue_sync_set_threshold(ue_sync_t *q, float threshold) {
|
||||
sync_set_threshold(&q->s, threshold, threshold/2);
|
||||
}
|
||||
|
||||
lte_cell_t ue_sync_get_cell(ue_sync_t *q) {
|
||||
return q->cell;
|
||||
}
|
||||
|
||||
pbch_mib_t ue_sync_get_mib(ue_sync_t *q) {
|
||||
return q->mib;
|
||||
}
|
||||
|
||||
uint32_t ue_sync_peak_idx(ue_sync_t *q) {
|
||||
return q->peak_idx;
|
||||
}
|
||||
|
||||
ue_sync_state_t ue_sync_get_state(ue_sync_t *q) {
|
||||
return q->state;
|
||||
}
|
||||
|
||||
static int update_srate(ue_sync_t *q) {
|
||||
struct timeval t[3];
|
||||
|
||||
gettimeofday(&t[1], NULL);
|
||||
if (sync_realloc(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) {
|
||||
fprintf(stderr, "Error realloc'ing SYNC\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
|
||||
if (NOF_MIB_DECODES > 1) {
|
||||
mib_decoder_free(q);
|
||||
if (mib_decoder_initialize(q)) {
|
||||
fprintf(stderr, "Error reinitializing MIB decoder\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally set the new sampling rate
|
||||
q->set_rate_callback(q->stream, (float) lte_sampling_freq_hz(q->cell.nof_prb));
|
||||
|
||||
ue_sync_reset(q);
|
||||
printf("Set sampling rate %.2f MHz, fft_size=%d, sf_len=%d Texec=%d us\n",
|
||||
(float) lte_sampling_freq_hz(q->cell.nof_prb)/1000000,
|
||||
CURRENT_FFTSIZE, CURRENT_SFLEN, (int) t[0].tv_usec);
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t ue_sync_get_sfidx(ue_sync_t *q) {
|
||||
return q->sf_idx;
|
||||
}
|
||||
|
||||
float ue_sync_get_cfo(ue_sync_t *q) {
|
||||
return 15000 * q->cur_cfo;
|
||||
}
|
||||
|
||||
float ue_sync_get_sfo(ue_sync_t *q) {
|
||||
return 1000*q->mean_time_offset/5;
|
||||
}
|
||||
|
||||
bool ue_sync_is_mib_decoded(ue_sync_t *q) {
|
||||
return q->pbch_decoded;
|
||||
}
|
||||
|
||||
void ue_sync_pbch_enable(ue_sync_t *q, bool enabled) {
|
||||
q->pbch_decoder_enabled = enabled;
|
||||
}
|
||||
|
||||
void ue_sync_pbch_always(ue_sync_t *q, bool enabled) {
|
||||
q->pbch_decode_always = enabled;
|
||||
}
|
||||
|
||||
void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
|
||||
q->decode_sss_on_track = enabled;
|
||||
}
|
||||
|
||||
static int mib_decoder_initialize(ue_sync_t *q) {
|
||||
|
||||
if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
return -1;
|
||||
}
|
||||
if (chest_init_LTEDL(&q->chest, q->cell)) {
|
||||
fprintf(stderr, "Error initializing reference signal\n");
|
||||
return -1;
|
||||
}
|
||||
if (pbch_init(&q->pbch, q->cell)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
return -1;
|
||||
}
|
||||
q->pbch_initialized = 1;
|
||||
DEBUG("PBCH initiated cell_id=%d\n", q->cell.id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mib_decoder_free(ue_sync_t *q) {
|
||||
chest_free(&q->chest);
|
||||
pbch_free(&q->pbch);
|
||||
lte_fft_free(&q->fft);
|
||||
}
|
||||
|
||||
static int mib_decoder_run(ue_sync_t *q) {
|
||||
int ret;
|
||||
|
||||
/* Run FFT for the second slot */
|
||||
lte_fft_run_sf(&q->fft, q->input_buffer, q->sf_symbols);
|
||||
|
||||
/* Get channel estimates of slot #1 for each port */
|
||||
chest_ce_sf(&q->chest, q->sf_symbols, q->ce, 0);
|
||||
|
||||
if (q->pbch_last_trial &&
|
||||
(q->frame_total_cnt - q->pbch_last_trial > 2))
|
||||
{
|
||||
pbch_decode_reset(&q->pbch);
|
||||
INFO("Resetting PBCH decoder: last trial %d, now is %d\n",
|
||||
q->pbch_last_trial, q->frame_total_cnt);
|
||||
q->pbch_last_trial = 0;
|
||||
}
|
||||
|
||||
if (pbch_decode(&q->pbch, q->sf_symbols, q->ce, &q->mib) == 1) {
|
||||
q->frame_number = q->mib.sfn;
|
||||
q->cell.nof_ports = q->mib.nof_ports;
|
||||
q->cell.nof_prb = q->mib.nof_prb;
|
||||
|
||||
if (!q->pbch_decoded) {
|
||||
printf("MIB decoded:\n");
|
||||
pbch_mib_fprint(stdout, &q->mib);
|
||||
ret = update_srate(q);
|
||||
} else {
|
||||
INFO("MIB decoded #%d SFN: %d\n", q->pbch_decoded, q->mib.sfn);
|
||||
}
|
||||
q->pbch_decoded++;
|
||||
|
||||
pbch_decode_reset(&q->pbch);
|
||||
|
||||
} else {
|
||||
INFO("MIB not decoded: %d\n", q->frame_total_cnt);
|
||||
q->pbch_last_trial = q->frame_total_cnt;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int find_peak_ok(ue_sync_t *q) {
|
||||
int ret;
|
||||
|
||||
if (q->peak_idx < CURRENT_SFLEN) {
|
||||
/* Receive the rest of the next subframe */
|
||||
if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (sync_sss_detected(&q->s)) {
|
||||
ret = sync_get_cell_id(&q->s);
|
||||
if (ret >= 0) {
|
||||
q->cell.id = (uint32_t) ret;
|
||||
q->cell.cp = sync_get_cp(&q->s);
|
||||
}
|
||||
|
||||
/* Get the subframe index (0 or 5) */
|
||||
q->sf_idx = sync_get_slot_id(&q->s)/2;
|
||||
|
||||
/* Reset variables */
|
||||
q->frame_ok_cnt = 0;
|
||||
q->frame_no_cnt = 0;
|
||||
q->frame_total_cnt = 0;
|
||||
|
||||
/* Goto Tracking state */
|
||||
q->state = SF_TRACK;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
|
||||
INFO("Found peak %d, SF_idx: %d, Cell_id: %d CP: %s\n",
|
||||
q->peak_idx, q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
|
||||
|
||||
if (q->peak_idx < CURRENT_SFLEN) {
|
||||
q->sf_idx++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
|
||||
int ret = LIBLTE_SUCCESS;
|
||||
|
||||
/* Make sure subframe idx is what we expect */
|
||||
if ((q->sf_idx != sync_get_slot_id(&q->s)/2) && q->decode_sss_on_track) {
|
||||
printf("\nWarning: Expected SF idx %d but got %d!\n",
|
||||
q->sf_idx, sync_get_slot_id(&q->s)/2);
|
||||
q->sf_idx = sync_get_slot_id(&q->s)/2;
|
||||
} else {
|
||||
q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE);
|
||||
|
||||
/* If the PSS peak is beyond the frame (we sample too slowly),
|
||||
discard the offseted samples to align next frame */
|
||||
if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) {
|
||||
ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset);
|
||||
} else {
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* compute cumulative moving average CFO */
|
||||
q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->s), q->cur_cfo, q->frame_ok_cnt);
|
||||
|
||||
/* compute cumulative moving average time offset */
|
||||
q->mean_time_offset = (float) EXPAVERAGE((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt);
|
||||
|
||||
q->peak_idx = CURRENT_SFLEN/2 + q->time_offset;
|
||||
q->frame_ok_cnt++;
|
||||
q->frame_no_cnt = 0;
|
||||
|
||||
|
||||
if (ret >= LIBLTE_SUCCESS) {
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int track_peak_no(ue_sync_t *q) {
|
||||
|
||||
/* if we missed too many PSS go back to FIND */
|
||||
q->frame_no_cnt++;
|
||||
if (q->frame_no_cnt >= TRACK_MAX_LOST) {
|
||||
printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt);
|
||||
q->state = SF_FIND;
|
||||
} else {
|
||||
INFO("Tracking peak not found, %d lost\n", (int) q->frame_no_cnt);
|
||||
}
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static int receive_samples(ue_sync_t *q) {
|
||||
|
||||
/* A negative time offset means there are samples in our buffer for the next subframe,
|
||||
because we are sampling too fast.
|
||||
*/
|
||||
if (q->time_offset < 0) {
|
||||
q->time_offset = -q->time_offset;
|
||||
}
|
||||
/* copy last part of the last subframe (use move since there could be overlapping) */
|
||||
memmove(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t));
|
||||
|
||||
/* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */
|
||||
if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* reset time offset */
|
||||
q->time_offset = 0;
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t track_idx;
|
||||
struct timeval t[3];
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
q->input_buffer != NULL)
|
||||
{
|
||||
|
||||
if (receive_samples(q)) {
|
||||
fprintf(stderr, "Error receiving samples\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (q->state) {
|
||||
case SF_FIND:
|
||||
q->s.sss_en = true;
|
||||
|
||||
/* Find peak and cell id */
|
||||
ret = sync_find(&q->s, q->input_buffer, &q->peak_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("Find PAR=%.2f\n", sync_get_peak_to_avg(&q->s));
|
||||
|
||||
if (ret == 1) {
|
||||
ret = find_peak_ok(q);
|
||||
/* Initialize PBCH decoder */
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
if (!q->pbch_initialized && q->pbch_decoder_enabled) {
|
||||
ret = mib_decoder_initialize(q);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error initializing MIB decoder\n");
|
||||
}
|
||||
}
|
||||
} else if (ret < 0) {
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error processing find peak \n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SF_TRACK:
|
||||
ret = LIBLTE_SUCCESS;
|
||||
|
||||
q->s.sss_en = q->decode_sss_on_track;
|
||||
|
||||
q->sf_idx = (q->sf_idx + 1) % 10;
|
||||
|
||||
DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt);
|
||||
|
||||
/* Every SF idx 0 and 5, find peak around known position q->peak_idx */
|
||||
if (q->sf_idx == 0 || q->sf_idx == 5) {
|
||||
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
gettimeofday(&t[1], NULL);
|
||||
#endif
|
||||
|
||||
track_idx = 0;
|
||||
|
||||
/* track pss around the middle of the subframe, where the PSS is */
|
||||
ret = sync_track(&q->s, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE, &track_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error tracking correlation peak\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
q->mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt);
|
||||
#endif
|
||||
|
||||
if (ret == 1) {
|
||||
ret = track_peak_ok(q, track_idx);
|
||||
} else {
|
||||
ret = track_peak_no(q);
|
||||
}
|
||||
|
||||
INFO("TRACK %3d: SF=%d Track_idx=%d Offset=%d CFO: %f\n",
|
||||
(int) q->frame_total_cnt, q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->s));
|
||||
|
||||
q->frame_total_cnt++;
|
||||
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
fprintf(stderr, "Error processing tracking peak\n");
|
||||
ue_sync_reset(q);
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do CFO Correction and deliver the frame */
|
||||
cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE);
|
||||
*sf_symbols = q->input_buffer;
|
||||
|
||||
/* At subframe 0, try to decode PBCH if not yet decoded */
|
||||
if (q->sf_idx == 0) {
|
||||
if(q->pbch_decoder_enabled &&
|
||||
(q->pbch_decoded < NOF_MIB_DECODES || q->pbch_decode_always))
|
||||
{
|
||||
mib_decoder_run(q);
|
||||
} else {
|
||||
q->mib.sfn = (q->mib.sfn + 1) % 1024;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
if (q->pbch_decoder_enabled) {
|
||||
if (q->pbch_decoded >= NOF_MIB_DECODES) {
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
DEBUG("UE SYNC returns %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_sync_reset(ue_sync_t *q) {
|
||||
q->state = SF_FIND;
|
||||
|
||||
q->pbch_last_trial = 0;
|
||||
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->time_offset = 0;
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
q->mean_exec_time = 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,244 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "liblte/phy/resampling/decim.h"
|
||||
#include "liblte/phy/resampling/resample_arb.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/sync/sync_frame.h"
|
||||
|
||||
|
||||
int sync_frame_init(sync_frame_t *q, uint32_t downsampling) {
|
||||
int ret = -1;
|
||||
bzero(q, sizeof(sync_frame_t));
|
||||
|
||||
if(sync_init(&q->s, SYNC_SF_LEN)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
sync_pss_det_peak_to_avg(&q->s);
|
||||
|
||||
if (cfo_init(&q->cfocorr, SYNC_SF_LEN * downsampling)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->input_buffer = malloc(2 * SYNC_SF_LEN * downsampling * sizeof(cf_t));
|
||||
if (!q->input_buffer) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->input_downsampled = malloc(SYNC_SF_LEN * sizeof(cf_t));
|
||||
if (!q->input_downsampled) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
resample_arb_init(&q->resample, (float) 1/downsampling);
|
||||
|
||||
q->downsampling = downsampling;
|
||||
sync_frame_reset(q);
|
||||
ret = 0;
|
||||
|
||||
clean_exit:
|
||||
if (ret == -1) {
|
||||
sync_frame_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sync_frame_free(sync_frame_t *q) {
|
||||
if (q->input_buffer) {
|
||||
free(q->input_buffer);
|
||||
}
|
||||
if (q->input_downsampled) {
|
||||
free(q->input_downsampled);
|
||||
}
|
||||
|
||||
cfo_free(&q->cfocorr);
|
||||
sync_free(&q->s);
|
||||
}
|
||||
|
||||
void sync_frame_run(sync_frame_t *q, cf_t *input) {
|
||||
uint32_t track_idx;
|
||||
|
||||
switch (q->state) {
|
||||
|
||||
case SF_FIND:
|
||||
q->peak_idx = sync_find(&q->s, input);
|
||||
q->cell_id = sync_get_cell_id(&q->s);
|
||||
|
||||
INFO("FIND %3d:\tPAR=%.2f\n", (int) q->frame_cnt, sync_get_peak_to_avg(&q->s));
|
||||
|
||||
if (q->peak_idx != -1 && q->cell_id != -1) {
|
||||
|
||||
/* Get the subframe index (0 or 5) */
|
||||
q->sf_idx = sync_get_slot_id(&q->s)/2;
|
||||
|
||||
/* Reset variables */
|
||||
q->last_found = 0;
|
||||
q->timeoffset = 0;
|
||||
q->frame_cnt = 0;
|
||||
|
||||
/* Goto Tracking state */
|
||||
q->state = SF_TRACK;
|
||||
}
|
||||
break;
|
||||
case SF_TRACK:
|
||||
|
||||
q->sf_idx = (q->sf_idx + 1) % 10;
|
||||
|
||||
/* Every SF idx 0 and 5, find peak around known position q->peak_idx */
|
||||
if (q->sf_idx != 0 && q->sf_idx != 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
assert(q->peak_idx < TRACK_LEN);
|
||||
|
||||
track_idx = sync_track(&q->s, &input[q->peak_idx - TRACK_LEN]);
|
||||
|
||||
INFO("TRACK %3d: SF=%d. Previous idx is %d New Offset is %d\n",
|
||||
(int) q->frame_cnt, q->sf_idx, q->peak_idx, track_idx - TRACK_LEN);
|
||||
|
||||
if (track_idx != -1) {
|
||||
INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx,
|
||||
sync_get_slot_id(&q->s)/2);
|
||||
|
||||
/* Make sure subframe idx is what we expect */
|
||||
if (q->sf_idx != sync_get_slot_id(&q->s)/2) {
|
||||
INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx,
|
||||
sync_get_slot_id(&q->s)/2);
|
||||
q->state = SF_FIND;
|
||||
}
|
||||
|
||||
/* compute cumulative moving average CFO */
|
||||
q->cur_cfo = (sync_get_cfo(&q->s) + q->frame_cnt * q->cur_cfo) / (q->frame_cnt + 1);
|
||||
|
||||
/* compute cumulative moving average time offset */
|
||||
q->timeoffset = (float) ((float) track_idx - TRACK_LEN + q->timeoffset * q->frame_cnt)
|
||||
/ (q->frame_cnt + 1);
|
||||
|
||||
q->last_found = q->frame_cnt;
|
||||
q->peak_idx = (q->peak_idx + track_idx - TRACK_LEN) % SYNC_SF_LEN;
|
||||
|
||||
if (q->peak_idx < 0) {
|
||||
INFO("PSS lost (peak_idx=%d). Going back to FIND\n", q->peak_idx);
|
||||
q->state = SF_FIND;
|
||||
}
|
||||
} else {
|
||||
/* if sync not found, adjust time offset with the averaged value */
|
||||
q->peak_idx = (q->peak_idx + (uint32_t) q->timeoffset) % SYNC_SF_LEN;
|
||||
|
||||
/* if we missed too many PSS go back to FIND */
|
||||
if (q->frame_cnt - q->last_found > TRACK_MAX_LOST) {
|
||||
INFO("%d frames lost. Going back to FIND", (int) q->frame_cnt - q->last_found);
|
||||
q->state = SF_FIND;
|
||||
}
|
||||
}
|
||||
q->frame_cnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sync_frame_set_threshold(sync_frame_t *q, float threshold) {
|
||||
sync_set_threshold(&q->s, threshold);
|
||||
}
|
||||
|
||||
uint32_t sync_frame_cell_id(sync_frame_t *q) {
|
||||
return q->cell_id;
|
||||
}
|
||||
|
||||
uint32_t sync_frame_sfidx(sync_frame_t *q) {
|
||||
return q->sf_idx;
|
||||
}
|
||||
|
||||
|
||||
int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output) {
|
||||
int retval = 0;
|
||||
int frame_start;
|
||||
cf_t *input_ds;
|
||||
uint32_t sf_len;
|
||||
|
||||
if (q->downsampling == 1) {
|
||||
input_ds = input;
|
||||
} else {
|
||||
//resample_arb_compute(&q->resample, input, q->input_downsampled, SYNC_SF_LEN * q->downsampling);
|
||||
decim_c(input, q->input_downsampled, q->downsampling, SYNC_SF_LEN * q->downsampling);
|
||||
input_ds = q->input_downsampled;
|
||||
}
|
||||
|
||||
sync_frame_run(q, input_ds);
|
||||
|
||||
sf_len = q->downsampling * SYNC_SF_LEN;
|
||||
|
||||
if (q->state == SF_FIND) {
|
||||
memcpy(q->input_buffer, input, sf_len * sizeof(cf_t));
|
||||
} else {
|
||||
frame_start = q->downsampling * q->peak_idx - sf_len/2;
|
||||
|
||||
DEBUG("Peak_idx=%d, frame_start=%d cfo=%.3f\n",q->peak_idx,
|
||||
frame_start, q->cur_cfo);
|
||||
|
||||
if (frame_start > 0) {
|
||||
if (q->fb_wp) {
|
||||
memcpy(&q->input_buffer[(sf_len - frame_start)], input, frame_start * sizeof(cf_t));
|
||||
memcpy(output, q->input_buffer, sf_len * sizeof(cf_t));
|
||||
retval = 1;
|
||||
}
|
||||
memcpy(q->input_buffer, &input[frame_start], (sf_len - frame_start) * sizeof(cf_t));
|
||||
q->fb_wp = true;
|
||||
} else {
|
||||
memcpy(output, &q->input_buffer[sf_len + frame_start], (-frame_start) * sizeof(cf_t));
|
||||
memcpy(&output[-frame_start], input, (sf_len + frame_start) * sizeof(cf_t));
|
||||
memcpy(&q->input_buffer[sf_len + frame_start], &input[sf_len + frame_start], (-frame_start) * sizeof(cf_t));
|
||||
retval = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Frequency Synchronization */
|
||||
if (retval) {
|
||||
cfo_correct(&q->cfocorr, output, -q->cur_cfo / 128);
|
||||
}
|
||||
|
||||
if (!retval) {
|
||||
DEBUG("Frame Buffered\n",0);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void sync_frame_reset(sync_frame_t *q) {
|
||||
q->state = SF_FIND;
|
||||
q->frame_cnt = 0;
|
||||
q->fb_wp = false;
|
||||
q->cur_cfo = 0;
|
||||
}
|
||||
|
@ -1,123 +0,0 @@
|
||||
%
|
||||
% Copyright 2011-2012 Ben Wojtowicz
|
||||
%
|
||||
% This program is free software: you can redistribute it and/or modify
|
||||
% it under the terms of the GNU Affero General Public License as published by
|
||||
% the Free Software Foundation, either version 3 of the License, or
|
||||
% (at your option) any later version.
|
||||
%
|
||||
% This program is distributed in the hope that it will be useful,
|
||||
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
% GNU Affero General Public License for more details.
|
||||
%
|
||||
% You should have received a copy of the GNU Affero General Public License
|
||||
% along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
%
|
||||
% Function: lte_generate_sss
|
||||
% Description: Generates LTE secondary synchronization signals
|
||||
% Inputs: N_id_1 - Physical layer cell identity group
|
||||
% N_id_2 - Physical layer identity
|
||||
% Outputs: sss_d_u_0 - The sequence d(n) used for the secondary
|
||||
% synchronization signal, an interleaved
|
||||
% concatenation of two length-31 binary
|
||||
% sequences for subframe 0
|
||||
% Outputs: sss_d_u_5 - The sequence d(n) used for the secondary
|
||||
% synchronization signal, an interleaved
|
||||
% concatenation of two length-31 binary
|
||||
% sequences for subframe 5
|
||||
% Spec: 3GPP TS 36.211 section 6.11.2.1 v10.1.0
|
||||
% Notes: None
|
||||
% Rev History: Ben Wojtowicz 10/28/2011 Created
|
||||
% Ben Wojtowicz 01/29/2012 Fixed license statement
|
||||
%
|
||||
function [sss_d_u_0, sss_d_u_5 c0 c1 m0 m1] = lte_generate_sss(N_id_1, N_id_2)
|
||||
% Validate N_id_1
|
||||
if(~(N_id_1 >= 0 && N_id_1 <= 167))
|
||||
fprintf('ERROR: Invalid N_id_1 (%u)\n', N_id_1);
|
||||
sss_d_u_0 = 0;
|
||||
sss_d_u_5 = 0;
|
||||
return;
|
||||
end
|
||||
|
||||
% Validate N_id_2
|
||||
if(~(N_id_2 >= 0 && N_id_2 <= 2))
|
||||
fprintf('ERROR: Invalid N_id_2 (%u)\n', N_id_2);
|
||||
sss_d_u_0 = 0;
|
||||
sss_d_u_5 = 0;
|
||||
return;
|
||||
end
|
||||
|
||||
% Generate m0 and m1
|
||||
q_prime = floor(N_id_1/30);
|
||||
q = floor((N_id_1 + (q_prime*(q_prime+1)/2))/30);
|
||||
m_prime = N_id_1 + (q*(q+1)/2);
|
||||
m0 = mod(m_prime, 31);
|
||||
m1 = mod((m0 + floor(m_prime/31) + 1), 31);
|
||||
|
||||
% Generate s_tilda
|
||||
x_s_tilda(0+1) = 0;
|
||||
x_s_tilda(1+1) = 0;
|
||||
x_s_tilda(2+1) = 0;
|
||||
x_s_tilda(3+1) = 0;
|
||||
x_s_tilda(4+1) = 1;
|
||||
for(i_hat=0:25)
|
||||
x_s_tilda(i_hat+5+1) = mod((x_s_tilda(i_hat+2+1) + x_s_tilda(i_hat+1)), 2);
|
||||
end
|
||||
for(idx=0:30)
|
||||
s_tilda(idx+1) = 1 - 2*x_s_tilda(idx+1);
|
||||
end
|
||||
|
||||
% Generate c_tilda
|
||||
x_c_tilda(0+1) = 0;
|
||||
x_c_tilda(1+1) = 0;
|
||||
x_c_tilda(2+1) = 0;
|
||||
x_c_tilda(3+1) = 0;
|
||||
x_c_tilda(4+1) = 1;
|
||||
for(i_hat=0:25)
|
||||
x_c_tilda(i_hat+5+1) = mod((x_c_tilda(i_hat+3+1) + x_c_tilda(i_hat+1)), 2);
|
||||
end
|
||||
for(idx=0:30)
|
||||
c_tilda(idx+1) = 1 - 2*x_c_tilda(idx+1);
|
||||
end
|
||||
|
||||
% Generate z_tilda
|
||||
x_z_tilda(0+1) = 0;
|
||||
x_z_tilda(1+1) = 0;
|
||||
x_z_tilda(2+1) = 0;
|
||||
x_z_tilda(3+1) = 0;
|
||||
x_z_tilda(4+1) = 1;
|
||||
for(i_hat=0:25)
|
||||
x_z_tilda(i_hat+5+1) = mod((x_z_tilda(i_hat+4+1) + x_z_tilda(i_hat+2+1) + x_z_tilda(i_hat+1+1) + x_z_tilda(i_hat+1)), 2);
|
||||
end
|
||||
for(idx=0:30)
|
||||
z_tilda(idx+1) = 1 - 2*x_z_tilda(idx+1);
|
||||
end
|
||||
|
||||
% Generate s0_m0 and s1_m1
|
||||
for(n=0:30)
|
||||
s0_m0(n+1) = s_tilda(mod(n + m0, 31)+1);
|
||||
s1_m1(n+1) = s_tilda(mod(n + m1, 31)+1);
|
||||
end
|
||||
|
||||
% Generate c0 and c1
|
||||
for(n=0:30)
|
||||
c0(n+1) = c_tilda(mod(n + N_id_2, 31)+1);
|
||||
c1(n+1) = c_tilda(mod(n + N_id_2 + 3, 31)+1);
|
||||
end
|
||||
|
||||
% Generate z1_m0 and z1_m1
|
||||
for(n=0:30)
|
||||
z1_m0(n+1) = z_tilda(mod(n + mod(m0, 8), 31)+1);
|
||||
z1_m1(n+1) = z_tilda(mod(n + mod(m1, 8), 31)+1);
|
||||
end
|
||||
|
||||
% Generate SSS
|
||||
for(n=0:30)
|
||||
sss_d_u_0(2*n+1) = s0_m0(n+1) * c0(n+1);
|
||||
sss_d_u_5(2*n+1) = s1_m1(n+1) * c0(n+1);
|
||||
|
||||
sss_d_u_0(2*n+1+1) = s1_m1(n+1) * c1(n+1) * z1_m0(n+1);
|
||||
sss_d_u_5(2*n+1+1) = s0_m0(n+1) * c1(n+1) * z1_m1(n+1);
|
||||
end
|
||||
end
|
@ -1,35 +0,0 @@
|
||||
N=128; %128 subcarries
|
||||
M=16; %QAM order
|
||||
cp=9; %length of the cyclic prefix... Is increasing the cyclic prefix size gonna increase the efficiency?
|
||||
scale = 1/sqrt(10);
|
||||
hMod = modem.qammod(M); %QAM Modulator
|
||||
hDemod = modem.qamdemod(hMod); %QAM demodulator
|
||||
loops = 10;
|
||||
SNR =0:5:35;
|
||||
t1= cputime ;
|
||||
% transmited signal. Contains N data points ranging from 0 to M-1
|
||||
ber=zeros(5,length(SNR));
|
||||
%% Creating the Rayleigh Multipath Channels
|
||||
Ch = rayleighchan(1/1000,10);
|
||||
Ch.ResetBeforeFiltering = 0;
|
||||
sig = 1i*ones(loops,1);
|
||||
h1 = filter(Ch,sig);
|
||||
h2 = 0.1072*filter(Ch,sig);
|
||||
h3 = 0.0120*filter(Ch,sig);
|
||||
h4 = 0.0052*filter(Ch,sig);
|
||||
% Delay Values
|
||||
l1 = 4;
|
||||
l2 = 7;
|
||||
l3= 16;
|
||||
%%
|
||||
ofdm_cp=[];
|
||||
%tx=transmited_data;
|
||||
for ik=1:loops%number of loops
|
||||
tx = randi([0 M-1],1,N); % generate random data
|
||||
sig=modulate(hMod, tx)*scale; % Modulate QAM modulated signal, devide by the square root of 10 to bring the average power of the signal to 1
|
||||
ofdm=sqrt(N).*ifft(sig,N); % generate OFDM signal IFFT on the parrellel data,multiply by sqrt(N) to adjust to the matlab computation ,
|
||||
ofdm_cp = [ofdm_cp ofdm(N-cp+1:N) ofdm]; % Add cyclic prefix
|
||||
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue