mirror of https://github.com/pvnis/srsRAN_4G.git
PSSS and SSSS implementation
parent
476f970ee1
commit
3fed21ce3e
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 SRSLTE_CHEST_SL_H
|
||||
#define SRSLTE_CHEST_SL_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "srslte/config.h"
|
||||
|
||||
#include "srslte/phy/ch_estimation/chest_common.h"
|
||||
#include "srslte/phy/ch_estimation/refsignal_ul.h"
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/resampling/interp.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
uint32_t nof_prb;
|
||||
uint32_t sf_n_re;
|
||||
|
||||
uint32_t M_sc_rs;
|
||||
int8_t nr_DMRS_symbols;
|
||||
|
||||
// Orthogonal Sequence (W) Transmission Mode 1, 2 and PSBCH
|
||||
int8_t* w;
|
||||
|
||||
// Cyclic Shift Values
|
||||
int8_t* n_CS;
|
||||
|
||||
// Refrence Signal Cyclic Shift
|
||||
float* alpha;
|
||||
|
||||
// Group Hopping Flag
|
||||
uint32_t f_gh;
|
||||
uint32_t* f_gh_pattern;
|
||||
uint32_t f_ss;
|
||||
|
||||
// Sequence Group Number
|
||||
uint32_t* u;
|
||||
|
||||
// Base Sequence Number - always 0 for sidelink
|
||||
uint32_t v;
|
||||
|
||||
int32_t N_zc;
|
||||
|
||||
int32_t* q;
|
||||
|
||||
float** r;
|
||||
|
||||
cf_t** r_uv;
|
||||
|
||||
cf_t** r_sequence;
|
||||
|
||||
cf_t** dmrs_received;
|
||||
cf_t* pilot_estimates_1;
|
||||
cf_t* pilot_estimates_2;
|
||||
cf_t* ce;
|
||||
|
||||
srslte_interp_linsrslte_vec_t lin_vec_sl;
|
||||
|
||||
} srslte_chest_sl_t;
|
||||
|
||||
int srslte_chest_sl_gen_psbch_dmrs(
|
||||
srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t nof_prb, uint32_t sf_idx, uint32_t N_sl_id);
|
||||
|
||||
int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q);
|
||||
|
||||
int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, cf_t* sf_buffer, srslte_sl_tm_t tx_mode, uint32_t nof_prb);
|
||||
void srslte_chest_sl_put_pscch_dmrs(
|
||||
srslte_chest_sl_t* q, uint32_t prb_idx, uint32_t nof_prb, cf_t* sf_buffer, srslte_sl_tm_t txMode);
|
||||
void srslte_chest_sl_put_pssch_dmrs(srslte_chest_sl_t* q,
|
||||
uint32_t prb_start,
|
||||
uint32_t prb_end,
|
||||
uint32_t prb_num,
|
||||
uint32_t nof_prb,
|
||||
cf_t* sf_buffer,
|
||||
srslte_sl_tm_t txMode);
|
||||
|
||||
void srslte_chest_sl_psbch_ls_estimate_equalize(srslte_chest_sl_t* q, cf_t* sf_buffer, cf_t* output, uint32_t nof_prb);
|
||||
|
||||
void srslte_chest_sl_free(srslte_chest_sl_t* q);
|
||||
|
||||
#endif
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 SRSLTE_PSBCH_H
|
||||
#define SRSLTE_PSBCH_H
|
||||
|
||||
#include <srslte/phy/dft/dft_precoding.h>
|
||||
#include <srslte/phy/fec/convcoder.h>
|
||||
#include <srslte/phy/fec/crc.h>
|
||||
#include <srslte/phy/fec/viterbi.h>
|
||||
#include <srslte/phy/modem/demod_soft.h>
|
||||
#include <srslte/phy/modem/modem_table.h>
|
||||
#include <srslte/phy/scrambling/scrambling.h>
|
||||
|
||||
#define SRSLTE_SL_BCH_CRC_LEN 16
|
||||
#define SRSLTE_SL_BCH_PAYLOAD_LEN 40
|
||||
#define SRSLTE_SL_BCH_PAYLOADCRC_LEN (SRSLTE_SL_BCH_PAYLOAD_LEN + SRSLTE_SL_BCH_CRC_LEN)
|
||||
#define SRSLTE_SL_BCH_ENCODED_LEN 3 * (SRSLTE_SL_BCH_PAYLOADCRC_LEN)
|
||||
|
||||
typedef struct {
|
||||
bool is_ue;
|
||||
uint32_t E;
|
||||
uint32_t Qm;
|
||||
uint32_t len_after_mod;
|
||||
uint32_t nof_prb;
|
||||
uint32_t nof_symbols;
|
||||
uint32_t N_sl_id;
|
||||
float precoding_scaling;
|
||||
uint32_t nof_prb_psbch;
|
||||
|
||||
// data
|
||||
uint8_t* a;
|
||||
|
||||
// crc
|
||||
uint32_t crc_poly;
|
||||
srslte_crc_t crc_mib;
|
||||
uint8_t* crc_temp;
|
||||
|
||||
// channel coding
|
||||
srslte_viterbi_t dec;
|
||||
srslte_convcoder_t encoder;
|
||||
uint8_t* d;
|
||||
|
||||
// rate matching
|
||||
uint8_t* e;
|
||||
int16_t* e_16;
|
||||
|
||||
// interleaving
|
||||
uint32_t* interleaver_lut;
|
||||
uint8_t* codeword;
|
||||
|
||||
// scrambling
|
||||
srslte_sequence_t seq;
|
||||
|
||||
// modulation
|
||||
srslte_modem_table_t mod;
|
||||
cf_t* symbols;
|
||||
float* llr;
|
||||
// layer mapping
|
||||
|
||||
// dft precoding
|
||||
srslte_dft_precoding_t dft_precoder;
|
||||
srslte_dft_precoding_t idft_precoder;
|
||||
cf_t* scfdma_symbols;
|
||||
|
||||
} srslte_psbch_t;
|
||||
|
||||
int srslte_psbch_init(srslte_psbch_t* q, uint32_t N_sl_id, uint32_t nof_prb);
|
||||
|
||||
void srslte_psbch_encode(srslte_psbch_t* q, uint8_t* mib_sl);
|
||||
int srslte_psbch_decode(srslte_psbch_t* q, uint8_t* mib_sl);
|
||||
|
||||
void srslte_psbch_put(srslte_psbch_t* q, cf_t* sf_buffer);
|
||||
void srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer);
|
||||
|
||||
void srslte_psbch_free(srslte_psbch_t* q);
|
||||
|
||||
#endif // SRSLTE_PSBCH_H
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: psss.h
|
||||
*
|
||||
* Description: Primary sidelink synchronization signal (PSSS) generation and detection.
|
||||
*
|
||||
*
|
||||
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.7.1
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSLTE_PSSS_H
|
||||
#define SRSLTE_PSSS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/dft/dft.h"
|
||||
|
||||
#define SRSLTE_PSSS_LEN 62
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
|
||||
cf_t psss_signal[2][SRSLTE_PSSS_LEN]; // One sequence for each N_id_2
|
||||
|
||||
cf_t** psss_sf_freq;
|
||||
|
||||
cf_t* input_pad_freq;
|
||||
cf_t* input_pad_time;
|
||||
|
||||
cf_t* dot_prod_output;
|
||||
cf_t* dot_prod_output_time;
|
||||
|
||||
cf_t* shifted_output;
|
||||
|
||||
float* shifted_output_abs;
|
||||
|
||||
int32_t corr_peak_pos;
|
||||
float corr_peak_value;
|
||||
|
||||
uint32_t N_id_2;
|
||||
|
||||
srslte_dft_plan_t plan_input;
|
||||
srslte_dft_plan_t plan_out;
|
||||
|
||||
} srslte_psss_t;
|
||||
|
||||
SRSLTE_API int srslte_psss_init(srslte_psss_t* q, uint32_t nof_prb, srslte_cp_t cp);
|
||||
|
||||
SRSLTE_API int srslte_psss_generate(cf_t* psss_signal, uint32_t N_id_2);
|
||||
|
||||
SRSLTE_API void srslte_psss_put_sf_buffer(cf_t* psss_signal, cf_t* sf_buffer, uint32_t nof_prb, srslte_cp_t cp);
|
||||
|
||||
SRSLTE_API int srslte_psss_find(srslte_psss_t* q, cf_t* input, uint32_t nof_prb, srslte_cp_t cp);
|
||||
|
||||
SRSLTE_API void srslte_psss_free(srslte_psss_t* q);
|
||||
|
||||
#endif // SRSLTE_PSSS_H
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: ssss.h
|
||||
*
|
||||
* Description: Secondary sidelink synchronization signal (SSSS) generation and detection.
|
||||
*
|
||||
*
|
||||
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.7.2
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSLTE_SSSS_H
|
||||
#define SRSLTE_SSSS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/dft/dft.h"
|
||||
|
||||
#define SRSLTE_SSSS_NOF_SEQ 336
|
||||
#define SRSLTE_SSSS_N 31
|
||||
#define SRSLTE_SSSS_LEN 2 * SRSLTE_SSSS_N
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
|
||||
float ssss_signal[SRSLTE_SSSS_NOF_SEQ][SRSLTE_SSSS_LEN]; // One sequence for each N_sl_id
|
||||
|
||||
cf_t** ssss_sf_freq;
|
||||
|
||||
cf_t* input_pad_freq;
|
||||
cf_t* input_pad_time;
|
||||
|
||||
cf_t* dot_prod_output;
|
||||
cf_t* dot_prod_output_time;
|
||||
|
||||
cf_t* shifted_output;
|
||||
|
||||
float* shifted_output_abs;
|
||||
|
||||
int32_t corr_peak_pos;
|
||||
float corr_peak_value;
|
||||
|
||||
uint32_t N_sl_id;
|
||||
|
||||
srslte_dft_plan_t plan_input;
|
||||
srslte_dft_plan_t plan_out;
|
||||
|
||||
} srslte_ssss_t;
|
||||
|
||||
SRSLTE_API int srslte_ssss_init(srslte_ssss_t* q, uint32_t nof_prb, srslte_cp_t cp, srslte_sl_tm_t tm);
|
||||
|
||||
SRSLTE_API void srslte_ssss_generate(float* ssss_signal, uint32_t N_sl_id, srslte_sl_tm_t tm);
|
||||
|
||||
SRSLTE_API void srslte_ssss_put_sf_buffer(float* ssss_signal, cf_t* sf_buffer, uint32_t nof_prb, srslte_cp_t cp);
|
||||
|
||||
SRSLTE_API int srslte_ssss_find(srslte_ssss_t* q, cf_t* input, uint32_t nof_prb, uint32_t N_id_2, srslte_cp_t cp);
|
||||
|
||||
SRSLTE_API void srslte_ssss_free(srslte_ssss_t* q);
|
||||
|
||||
#endif
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 SRSLTE_UE_SL_MIB_H
|
||||
#define SRSLTE_UE_SL_MIB_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SRSLTE_MIB_SL_MAX_LEN 40
|
||||
|
||||
// 3GPP TS 36.331 Sec. 6.5.2
|
||||
typedef struct SRSLTE_API {
|
||||
|
||||
// sl-Bandwidth-r12 enum {6, 15, 25, 50, 75, 100} (3 bits)
|
||||
uint32_t sl_bandwidth_r12;
|
||||
|
||||
// tdd-ConfigSL-r12 (3 bits)
|
||||
uint32_t tdd_config_sl_r12;
|
||||
|
||||
// directFrameNumber-r12 (10 bits)
|
||||
uint32_t direct_frame_number_r12;
|
||||
|
||||
// directSubframeNumber-r12 (4 bits)
|
||||
uint32_t direct_subframe_number_r12;
|
||||
|
||||
// inCoverage-r12 (1 bit)
|
||||
bool in_coverage_r12;
|
||||
|
||||
// reserved-r12 (19 bits)
|
||||
|
||||
} srslte_ue_mib_sl_t;
|
||||
|
||||
int srslte_ue_mib_sl_set(srslte_ue_mib_sl_t* q,
|
||||
uint32_t nof_prb,
|
||||
uint32_t tdd_config,
|
||||
uint32_t direct_frame_number,
|
||||
uint32_t direct_subframe_number,
|
||||
bool in_coverage);
|
||||
|
||||
void srslte_ue_mib_sl_pack(srslte_ue_mib_sl_t *q, uint8_t *msg);
|
||||
void srlste_ue_mib_sl_unpack(srslte_ue_mib_sl_t *q, uint8_t *msg);
|
||||
|
||||
void srslte_ue_mib_sl_free(srslte_ue_mib_sl_t* q);
|
||||
|
||||
#endif // SRSLTE_UE_SL_MIB_H
|
@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <complex.h>
|
||||
#include <math.h>
|
||||
#include <srslte/phy/common/phy_common.h>
|
||||
#include <srslte/phy/mimo/precoding.h>
|
||||
#include <srslte/phy/utils/debug.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/ch_estimation/chest_sl.h"
|
||||
#include "srslte/phy/dft/dft_precoding.h"
|
||||
#include "srslte/phy/utils/convolution.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include "ul_rs_tables.h"
|
||||
|
||||
#define NOF_PRIME_NUMBERS_SL 196
|
||||
#define SRSLTE_SL_MAX_DMRS 4
|
||||
#define SRSLTE_SL_MAX_M_SC_RS 100 * 12
|
||||
|
||||
static uint32_t get_q(uint32_t u, uint32_t v, uint32_t N_sz)
|
||||
{
|
||||
float q;
|
||||
float q_hat;
|
||||
float n_sz = (float)N_sz;
|
||||
|
||||
q_hat = n_sz * (u + 1) / 31;
|
||||
if ((((uint32_t)(2 * q_hat)) % 2) == 0) {
|
||||
q = q_hat + 0.5 + v;
|
||||
} else {
|
||||
q = q_hat + 0.5 - v;
|
||||
}
|
||||
return (uint32_t)q;
|
||||
}
|
||||
|
||||
static void interpolate_pilots_sl_psbch(srslte_interp_linsrslte_vec_t* q, cf_t* ce, uint32_t n_prb)
|
||||
{
|
||||
uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, SRSLTE_CP_NORM);
|
||||
uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, SRSLTE_CP_NORM);
|
||||
uint32_t NL = 2 * SRSLTE_CP_NSYMB(SRSLTE_CP_NORM);
|
||||
|
||||
uint32_t nre = n_prb * SRSLTE_NRE;
|
||||
|
||||
srslte_interp_linear_vector_resize(q, nre);
|
||||
|
||||
uint32_t ce_l1 = SRSLTE_RE_IDX(n_prb, L1, 0 * SRSLTE_NRE);
|
||||
uint32_t ce_l2 = SRSLTE_RE_IDX(n_prb, L2, 0 * SRSLTE_NRE);
|
||||
|
||||
srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L2 - L1), L1, false, nre);
|
||||
srslte_interp_linear_vector3(q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L2 - L1), (L2 - L1) - 1, true, nre);
|
||||
srslte_interp_linear_vector3(
|
||||
q, &ce[ce_l1], &ce[ce_l2], &ce[ce_l2], &ce[ce_l2 + nre], (L2 - L1), (NL - L2) - 1, true, nre);
|
||||
}
|
||||
|
||||
// TS36.211 S9.8 Table 9.8-2: Reference signal parameters for PSCCH
|
||||
int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q, uint32_t N_sa_id)
|
||||
{
|
||||
srslte_interp_linear_vector_init(&q->lin_vec_sl, SRSLTE_MAX_PRB * SRSLTE_NRE);
|
||||
|
||||
q->n_CS = srslte_vec_malloc(sizeof(int8_t) * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->n_CS) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->alpha = srslte_vec_malloc(sizeof(float) * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->alpha) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->w = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->w) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->q = srslte_vec_malloc(sizeof(uint32_t) * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->q) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->r = (float**)srslte_vec_malloc(sizeof(float*) * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->r) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; i++) {
|
||||
q->r[i] = srslte_vec_malloc(sizeof(float) * SRSLTE_MAX_PRB * SRSLTE_NRE);
|
||||
if (!q->r[i]) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
q->r_uv = (cf_t**)srslte_vec_malloc(sizeof(cf_t*) * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->r_uv) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; i++) {
|
||||
q->r_uv[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE);
|
||||
if (!q->r_uv[i]) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
q->r_sequence = (cf_t**)srslte_vec_malloc(sizeof(cf_t*) * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->r_sequence) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; i++) {
|
||||
q->r_sequence[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE);
|
||||
if (!q->r_sequence[i]) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
q->u = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS);
|
||||
if (!q->u) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS); // MAX PERIOD LENGTH 320
|
||||
if (!q->f_gh_pattern) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_group_hopping_f_gh(q->f_gh_pattern, N_sa_id);
|
||||
|
||||
q->ce = srslte_vec_malloc(sizeof(cf_t) * 100 * 12 * 14);
|
||||
if (!q->ce) {
|
||||
ERROR("Error allocating memmory");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q)
|
||||
{
|
||||
return srslte_chest_sl_init_dmrs(q, 0);
|
||||
}
|
||||
|
||||
int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
|
||||
srslte_sl_tm_t txMode,
|
||||
uint32_t nof_prb,
|
||||
srslte_sl_channels_t ch,
|
||||
uint32_t sf_idx,
|
||||
uint32_t N_sl_id,
|
||||
uint32_t available_pool_rbs,
|
||||
uint32_t N_sa_id)
|
||||
{
|
||||
// M_sc_rs - Reference Signal Length
|
||||
switch (ch) {
|
||||
case SRSLTE_SIDELINK_PSBCH:
|
||||
q->M_sc_rs = 72;
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSCCH:
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
q->M_sc_rs = 12;
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
q->M_sc_rs = 24;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSSCH:
|
||||
q->M_sc_rs = available_pool_rbs;
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSDCH:
|
||||
printf("channel not supported yet\n\n");
|
||||
break;
|
||||
default:
|
||||
printf("channel not supported yet\n\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// nr_DMRS_symbols
|
||||
switch (txMode) {
|
||||
case SRSLTE_SIDELINK_TM1:
|
||||
case SRSLTE_SIDELINK_TM2:
|
||||
q->nr_DMRS_symbols = 2;
|
||||
break;
|
||||
case SRSLTE_SIDELINK_TM3:
|
||||
case SRSLTE_SIDELINK_TM4:
|
||||
printf("transmission mode not supported yet\n");
|
||||
return SRSLTE_ERROR;
|
||||
default:
|
||||
printf("transmission mode not supported \n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// n_CS - Cyclic Shift
|
||||
switch (ch) {
|
||||
case SRSLTE_SIDELINK_PSBCH:
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
q->n_CS[i] = (int)(N_sl_id / 2) % 8;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSCCH:
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
q->n_CS[i] = 0;
|
||||
}
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
q->n_CS[i] = i * 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSSCH:
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
q->n_CS[i] = (int)(N_sa_id / 2) % 8;
|
||||
}
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSDCH:
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
q->n_CS[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// alpha - Reference Signal Cyclic Shift
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; ++i) {
|
||||
q->alpha[i] = (2 * M_PI * q->n_CS[i]) / 12;
|
||||
}
|
||||
|
||||
// Group Hopping
|
||||
// Base Sequence Number - always 0 for sidelink
|
||||
q->v = 0;
|
||||
switch (ch) {
|
||||
case SRSLTE_SIDELINK_PSBCH:
|
||||
q->f_gh = 0;
|
||||
q->f_ss = (N_sl_id / 16) % 30;
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; ++i) {
|
||||
q->u[i] = (q->f_gh + q->f_ss) % 30;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSCCH:
|
||||
q->f_gh = 0;
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
q->f_ss = 0;
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
q->f_ss = 8;
|
||||
}
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; ++i) {
|
||||
q->u[i] = (q->f_gh + q->f_ss) % 30;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSSCH:
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
q->f_gh = 1;
|
||||
q->f_ss = N_sa_id % 30;
|
||||
|
||||
uint8_t i = 0;
|
||||
for (uint32_t ns = 2 * sf_idx; ns < 2 * (sf_idx + 1); ns++) {
|
||||
uint32_t f_gh = q->f_gh_pattern[ns];
|
||||
|
||||
uint32_t delta_ss = 0;
|
||||
q->u[i++] = (f_gh + (N_sa_id % 30) + delta_ss) % 30;
|
||||
}
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
q->f_gh = 1;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSDCH:
|
||||
q->f_gh = 0;
|
||||
q->f_ss = 0;
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; ++i) {
|
||||
q->u[i] = (q->f_gh + q->f_ss) % 30;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// N_zc - Zadoff Chu Sequence Length
|
||||
switch (q->M_sc_rs / SRSLTE_NRE) {
|
||||
case 1:
|
||||
for (int j = 0; j < q->nr_DMRS_symbols; ++j) {
|
||||
for (int i = 0; i < SRSLTE_NRE; i++) {
|
||||
q->r[j][i] = phi_M_sc_12[q->u[j]][i] * M_PI / 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int j = 0; j < q->nr_DMRS_symbols; ++j) {
|
||||
for (int i = 0; i < q->M_sc_rs; i++) {
|
||||
q->r[j][i] = phi_M_sc_24[q->u[j]][i] * M_PI / 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (uint32_t i = NOF_PRIME_NUMBERS_SL - 1; i > 0; i--) {
|
||||
if (prime_numbers[i] < q->M_sc_rs) {
|
||||
q->N_zc = prime_numbers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < q->nr_DMRS_symbols; ++j) {
|
||||
q->q[j] = get_q(q->u[j], q->v, q->N_zc);
|
||||
float n_sz = (float)q->N_zc;
|
||||
for (uint32_t i = 0; i < q->M_sc_rs; i++) {
|
||||
float m = (float)(i % q->N_zc);
|
||||
q->r[j][i] = -M_PI * q->q[j] * m * (m + 1) / n_sz;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// Do complex exponential and adjust amplitude
|
||||
for (int j = 0; j < q->nr_DMRS_symbols; ++j) {
|
||||
for (int i = 0; i < q->M_sc_rs; i++) {
|
||||
q->r_uv[j][i] = cexpf(I * (q->r[j][i] + q->alpha[0] * i));
|
||||
}
|
||||
}
|
||||
|
||||
// w - Orthogonal Sequence
|
||||
switch (ch) {
|
||||
case SRSLTE_SIDELINK_PSBCH:
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
if (N_sl_id % 2) {
|
||||
q->w[0] = 1;
|
||||
q->w[1] = -1;
|
||||
} else {
|
||||
q->w[0] = 1;
|
||||
q->w[1] = 1;
|
||||
}
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
printf("transmission mode not supported \n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSCCH:
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
q->w[0] = 1;
|
||||
q->w[1] = 1;
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
printf("transmission mode not supported \n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SIDELINK_PSSCH:
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
if (N_sa_id % 2 == 0) {
|
||||
q->w[0] = 1;
|
||||
q->w[1] = 1;
|
||||
} else {
|
||||
q->w[0] = 1;
|
||||
q->w[1] = -1;
|
||||
}
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
printf("transmission mode not supported \n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
for (int j = 0; j < q->nr_DMRS_symbols; j++) {
|
||||
for (int i = 0; i < q->M_sc_rs; i++) {
|
||||
q->r_sequence[j][i] = q->w[j] * q->r_uv[j][i];
|
||||
}
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_chest_sl_gen_psbch_dmrs(
|
||||
srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t nof_prb, uint32_t sf_idx, uint32_t N_sl_id)
|
||||
{
|
||||
return srslte_chest_sl_gen_dmrs(q, txMode, nof_prb, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0);
|
||||
}
|
||||
|
||||
int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, cf_t* sf_buffer, srslte_sl_tm_t tx_mode, uint32_t nof_prb)
|
||||
{
|
||||
int sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * nof_prb * 2;
|
||||
if (tx_mode == SRSLTE_SIDELINK_TM1 || tx_mode == SRSLTE_SIDELINK_TM2) {
|
||||
int k = (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) - 4) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 36;
|
||||
memcpy(&sf_buffer[k], &q->r_sequence[0][0], q->M_sc_rs * sizeof(cf_t));
|
||||
memcpy(&sf_buffer[k + sf_n_re / 2], &q->r_sequence[1][0], q->M_sc_rs * sizeof(cf_t));
|
||||
} else if (tx_mode == SRSLTE_SIDELINK_TM3 || tx_mode == SRSLTE_SIDELINK_TM4) {
|
||||
printf("transmission mode not supported yet\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void srslte_chest_sl_put_pscch_dmrs(
|
||||
srslte_chest_sl_t* q, uint32_t prb_idx, uint32_t nof_prb, cf_t* sf_buffer, srslte_sl_tm_t txMode)
|
||||
{
|
||||
uint32_t l = 3;
|
||||
uint32_t k = prb_idx * SRSLTE_NRE;
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
memcpy(&sf_buffer[k + l * SRSLTE_NRE * nof_prb], q->r_sequence[i], q->M_sc_rs * sizeof(cf_t));
|
||||
l += 7;
|
||||
}
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
l = 2;
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
memcpy(&sf_buffer[k + l * SRSLTE_NRE * nof_prb], q->r_sequence[i], q->M_sc_rs * sizeof(cf_t));
|
||||
l += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_chest_sl_put_pssch_dmrs(srslte_chest_sl_t* q,
|
||||
uint32_t prb_start,
|
||||
uint32_t prb_end,
|
||||
uint32_t prb_num,
|
||||
uint32_t nof_prb,
|
||||
cf_t* sf_buffer,
|
||||
srslte_sl_tm_t txMode)
|
||||
{
|
||||
uint32_t k = prb_start * SRSLTE_NRE;
|
||||
if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) {
|
||||
uint32_t l = 3;
|
||||
for (int i = 0; i < q->nr_DMRS_symbols; i++) {
|
||||
memcpy(&sf_buffer[k + l * nof_prb * SRSLTE_NRE], q->r_sequence[i], q->M_sc_rs / 2 * sizeof(cf_t));
|
||||
k = ((prb_end + 1) * SRSLTE_NRE) - (prb_num * SRSLTE_NRE);
|
||||
memcpy(
|
||||
&sf_buffer[k + l * nof_prb * SRSLTE_NRE], &q->r_sequence[i][q->M_sc_rs / 2], q->M_sc_rs / 2 * sizeof(cf_t));
|
||||
l += 7;
|
||||
}
|
||||
} else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) {
|
||||
printf("Transmission Mode not supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_chest_sl_psbch_ls_estimate_equalize(srslte_chest_sl_t* q, cf_t* sf_buffer, cf_t* output, uint32_t nof_prb)
|
||||
{
|
||||
|
||||
int sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * nof_prb * 2;
|
||||
|
||||
// Get Demodulation Reference Signals from resource grid
|
||||
int k = (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) - 4) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 36;
|
||||
|
||||
bzero(q->ce, sizeof(cf_t) * sf_n_re);
|
||||
|
||||
// Get Pilot Estimates
|
||||
// Use the known DMRS signal to compute least-squares estimates
|
||||
srslte_vec_prod_conj_ccc(&sf_buffer[k], &q->r_sequence[0][0], &q->ce[k], q->M_sc_rs);
|
||||
srslte_vec_prod_conj_ccc(&sf_buffer[k + sf_n_re / 2], &q->r_sequence[1][0], &q->ce[k + sf_n_re / 2], q->M_sc_rs);
|
||||
|
||||
interpolate_pilots_sl_psbch(&q->lin_vec_sl, q->ce, nof_prb);
|
||||
|
||||
// Perform channel equalization
|
||||
srslte_predecoding_single(sf_buffer, q->ce, output, NULL, sf_n_re, 1, 0.0);
|
||||
}
|
||||
|
||||
void srslte_chest_sl_free(srslte_chest_sl_t* q)
|
||||
{
|
||||
srslte_interp_linear_vector_free(&q->lin_vec_sl);
|
||||
if (q->w) {
|
||||
free(q->w);
|
||||
}
|
||||
if (q->n_CS) {
|
||||
free(q->n_CS);
|
||||
}
|
||||
if (q->q) {
|
||||
free(q->q);
|
||||
}
|
||||
if (q->alpha) {
|
||||
free(q->alpha);
|
||||
}
|
||||
if (q->r) {
|
||||
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) {
|
||||
free(q->r[i]);
|
||||
}
|
||||
free(q->r);
|
||||
}
|
||||
if (q->r_uv) {
|
||||
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) {
|
||||
free(q->r_uv[i]);
|
||||
}
|
||||
free(q->r_uv);
|
||||
}
|
||||
if (q->r_sequence) {
|
||||
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) {
|
||||
free(q->r_sequence[i]);
|
||||
}
|
||||
free(q->r_sequence);
|
||||
}
|
||||
if (q->u) {
|
||||
free(q->u);
|
||||
}
|
||||
if (q->f_gh_pattern) {
|
||||
free(q->f_gh_pattern);
|
||||
}
|
||||
if (q->ce) {
|
||||
free(q->ce);
|
||||
}
|
||||
}
|
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <srslte/phy/phch/psbch.h>
|
||||
|
||||
#include <srslte/phy/fec/rm_conv.h>
|
||||
#include <srslte/phy/modem/mod.h>
|
||||
#include <srslte/phy/utils/bit.h>
|
||||
#include <srslte/phy/utils/debug.h>
|
||||
#include <srslte/phy/utils/vector.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void slbch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm, uint32_t* interleaver_lut)
|
||||
{
|
||||
uint32_t NL = 1;
|
||||
uint32_t Cmux = N_pusch_symbs;
|
||||
uint32_t Rmux = H_prime_total * Qm * NL / Cmux;
|
||||
uint32_t y_indices[Rmux][Cmux];
|
||||
|
||||
for (int i = 0; i < Rmux; i++) {
|
||||
for (int k = 0; k < Cmux; k++) {
|
||||
y_indices[i][k] = Rmux * k + i;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t arrayIdx = 0;
|
||||
for (int i = 0; i < Rmux; i += 2) {
|
||||
for (int k = 0; k < Cmux; k++) {
|
||||
interleaver_lut[arrayIdx++] = y_indices[i][k];
|
||||
interleaver_lut[arrayIdx++] = y_indices[i + 1][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_psbch_init(srslte_psbch_t* q, uint32_t N_sl_id, uint32_t nof_prb)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL) {
|
||||
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
q->nof_prb = nof_prb;
|
||||
q->N_sl_id = N_sl_id;
|
||||
|
||||
q->nof_prb_psbch = 6;
|
||||
|
||||
q->a = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_BCH_PAYLOADCRC_LEN);
|
||||
if (!q->a) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->d = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_BCH_ENCODED_LEN);
|
||||
if (!q->d) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
bzero(q->d, sizeof(uint8_t) * SRSLTE_SL_BCH_ENCODED_LEN);
|
||||
|
||||
// crc
|
||||
q->crc_poly = 0x11021;
|
||||
if (srslte_crc_init(&q->crc_mib, q->crc_poly, SRSLTE_SL_BCH_CRC_LEN)) {
|
||||
ERROR("Error crc init");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->crc_temp = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_BCH_CRC_LEN);
|
||||
if (!q->crc_temp) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// channel coding
|
||||
q->encoder.K = 7;
|
||||
q->encoder.R = 3;
|
||||
q->encoder.tail_biting = true;
|
||||
int poly[3] = {0x6D, 0x4F, 0x57};
|
||||
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
|
||||
|
||||
// channel decoding
|
||||
if (srslte_viterbi_init(&q->dec, SRSLTE_VITERBI_37, poly, 56, true)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// rate matching
|
||||
q->nof_symbols = 8;
|
||||
q->E = q->nof_symbols * SRSLTE_NRE * q->nof_prb_psbch * 2;
|
||||
q->e = srslte_vec_malloc(sizeof(uint8_t) * q->E);
|
||||
if (!q->e) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->e_16 = srslte_vec_malloc(sizeof(int16_t) * q->E);
|
||||
if (!q->e_16) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
bzero(q->e, sizeof(uint8_t) * q->E);
|
||||
|
||||
// interleaving
|
||||
q->Qm = 2; // Always QPSK
|
||||
q->interleaver_lut = srslte_vec_malloc(sizeof(uint32_t) * q->E);
|
||||
if (!q->interleaver_lut) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
slbch_interleave_gen(q->E / 2, q->nof_symbols, q->Qm, q->interleaver_lut);
|
||||
q->codeword = srslte_vec_malloc(sizeof(uint8_t) * q->E);
|
||||
if (!q->codeword) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// scrambling
|
||||
bzero(&q->seq, sizeof(srslte_sequence_t));
|
||||
srslte_sequence_LTE_pr(&q->seq, q->E, q->N_sl_id);
|
||||
|
||||
// modulation
|
||||
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->len_after_mod = q->E / q->mod.nbits_x_symbol;
|
||||
q->symbols = srslte_vec_malloc(sizeof(cf_t) * q->len_after_mod);
|
||||
if (!q->symbols) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
bzero(q->symbols, sizeof(cf_t) * q->len_after_mod);
|
||||
|
||||
q->llr = srslte_vec_malloc(sizeof(float) * q->E);
|
||||
if (!q->llr) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
bzero(q->llr, sizeof(float) * q->E);
|
||||
|
||||
// dft precoding
|
||||
q->precoding_scaling = 1.0;
|
||||
if (srslte_dft_precoding_init(&q->dft_precoder, q->nof_prb_psbch, true)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->scfdma_symbols = srslte_vec_malloc(sizeof(cf_t) * q->len_after_mod);
|
||||
if (!q->scfdma_symbols) {
|
||||
ERROR("Error allocating memmory\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
bzero(q->scfdma_symbols, sizeof(cf_t) * q->len_after_mod);
|
||||
|
||||
// idft predecoding
|
||||
if (srslte_dft_precoding_init(&q->idft_precoder, q->nof_prb_psbch, false)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void srslte_psbch_encode(srslte_psbch_t* q, uint8_t* mib_sl)
|
||||
{
|
||||
// ********************************************************************************************************
|
||||
// SL-BCH Processing
|
||||
// ********************************************************************************************************
|
||||
|
||||
// CRC Attachment
|
||||
memcpy(q->a, mib_sl, sizeof(uint8_t) * SRSLTE_SL_BCH_PAYLOAD_LEN);
|
||||
srslte_crc_attach(&q->crc_mib, q->a, SRSLTE_SL_BCH_PAYLOAD_LEN);
|
||||
|
||||
// Channel Coding
|
||||
srslte_convcoder_encode(&q->encoder, q->a, q->d, SRSLTE_SL_BCH_PAYLOADCRC_LEN);
|
||||
|
||||
// Rate matching
|
||||
q->nof_symbols = 8;
|
||||
q->E = q->nof_symbols * (SRSLTE_NRE * q->nof_prb_psbch) * 2;
|
||||
srslte_rm_conv_tx(q->d, SRSLTE_SL_BCH_ENCODED_LEN, q->e, q->E);
|
||||
|
||||
// Interleaving
|
||||
for (int i = 0; i < q->E; i++) {
|
||||
q->codeword[i] = (uint8_t)q->e[q->interleaver_lut[i]];
|
||||
}
|
||||
|
||||
// ********************************************************************************************************
|
||||
// PSBCH Processing
|
||||
// ********************************************************************************************************
|
||||
|
||||
// Scrambling
|
||||
srslte_scrambling_b(&q->seq, q->codeword);
|
||||
|
||||
// Modulation
|
||||
srslte_mod_modulate(&q->mod, q->codeword, q->symbols, q->E);
|
||||
|
||||
// Layer Mapping - TS 36.211 SEC 9.6.3 - Single layer
|
||||
|
||||
// DFT Precoding
|
||||
srslte_dft_precoding(&q->dft_precoder, q->symbols, q->scfdma_symbols, q->nof_prb_psbch, q->nof_symbols);
|
||||
|
||||
// Precoding - TS 36.211 SEC 9.6.5 - Single antenna port
|
||||
}
|
||||
|
||||
void srslte_psbch_put(srslte_psbch_t* q, cf_t* sf_buffer)
|
||||
{
|
||||
uint32_t samplePos = 0;
|
||||
uint32_t k = q->nof_prb * SRSLTE_NRE / 2 - 36;
|
||||
|
||||
// Mapping to physical resources
|
||||
for (uint32_t i = 0; i < SRSLTE_CP_NORM_SF_NSYMB; i++) {
|
||||
if (i == 1 || i == 2 || i == 3 || i == 10 || i == 11 || i == 12) {
|
||||
continue;
|
||||
}
|
||||
memcpy(&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE],
|
||||
&q->scfdma_symbols[samplePos],
|
||||
(SRSLTE_NRE * q->nof_prb_psbch) * sizeof(cf_t));
|
||||
samplePos += (SRSLTE_NRE * q->nof_prb_psbch);
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer)
|
||||
{
|
||||
uint32_t samplePos = 0;
|
||||
uint32_t k = q->nof_prb * SRSLTE_NRE / 2 - 36;
|
||||
|
||||
// Get PSBCH RE's
|
||||
for (uint32_t i = 0; i < SRSLTE_CP_NORM_SF_NSYMB; i++) {
|
||||
if (i == 1 || i == 2 || i == 3 || i == 10 || i == 11 || i == 12) {
|
||||
continue;
|
||||
}
|
||||
memcpy(&q->scfdma_symbols[samplePos],
|
||||
&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE],
|
||||
(SRSLTE_NRE * q->nof_prb_psbch) * sizeof(cf_t));
|
||||
samplePos += (SRSLTE_NRE * q->nof_prb_psbch);
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_psbch_decode(srslte_psbch_t* q, uint8_t* mib_sl)
|
||||
{
|
||||
// ********************************************************************************************************
|
||||
// PSBCH Processing
|
||||
// ********************************************************************************************************
|
||||
|
||||
// Precoding - TS 36.211 SEC 9.6.5 - Single antenna port Skipped
|
||||
|
||||
// IDFT Precoding
|
||||
q->len_after_mod = q->E / q->Qm;
|
||||
srslte_dft_precoding(&q->idft_precoder, q->scfdma_symbols, q->symbols, q->nof_prb_psbch, q->nof_symbols);
|
||||
|
||||
// Layer Mapping - TS 36.211 SEC 9.6.3 - Single layer Skipped
|
||||
|
||||
// Demodulation
|
||||
srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->symbols, q->llr, q->len_after_mod);
|
||||
|
||||
// Descramble
|
||||
for (int i = 0; i < q->E; i++) {
|
||||
q->codeword[i] = q->llr[i] > 0 ? (uint8_t)1 : (uint8_t)0;
|
||||
}
|
||||
srslte_scrambling_b(&q->seq, q->codeword);
|
||||
|
||||
// TS 36.211 Section 9.3.2: The last SC-FDMA symbol in a sidelink subframe serves as a guard period and shall not be
|
||||
// used for sidelink transmission.
|
||||
bzero(&q->codeword[1008], sizeof(uint8_t) * 144);
|
||||
|
||||
// ********************************************************************************************************
|
||||
// SL-BCH Processing
|
||||
// ********************************************************************************************************
|
||||
|
||||
// Deinterleaving
|
||||
for (int i = 0; i < q->E; i++) {
|
||||
q->e_16[q->interleaver_lut[i]] = q->codeword[i];
|
||||
}
|
||||
|
||||
// Unrate Matching
|
||||
float input_rm_rate_matching[q->E];
|
||||
float output_rm_rate_matching[SRSLTE_SL_BCH_ENCODED_LEN];
|
||||
for (int i = 0; i < q->E; i++) {
|
||||
input_rm_rate_matching[i] = (float)q->e_16[i];
|
||||
}
|
||||
srslte_rm_conv_rx(input_rm_rate_matching, q->E, output_rm_rate_matching, SRSLTE_SL_BCH_ENCODED_LEN);
|
||||
|
||||
// Channel Decoding
|
||||
uint16_t decoder_input[SRSLTE_SL_BCH_ENCODED_LEN];
|
||||
srslte_vec_quant_fus(output_rm_rate_matching, decoder_input, 8192, 32767.5, 65535, SRSLTE_SL_BCH_ENCODED_LEN);
|
||||
srslte_viterbi_decode_us(&q->dec, decoder_input, q->a, SRSLTE_SL_BCH_PAYLOADCRC_LEN);
|
||||
|
||||
// RM CRC
|
||||
memcpy(q->crc_temp, &q->a[SRSLTE_SL_BCH_PAYLOAD_LEN], sizeof(uint8_t) * SRSLTE_SL_BCH_CRC_LEN);
|
||||
srslte_crc_attach(&q->crc_mib, q->a, SRSLTE_SL_BCH_PAYLOAD_LEN);
|
||||
if (srslte_bit_diff(q->crc_temp, &q->a[SRSLTE_SL_BCH_PAYLOAD_LEN], SRSLTE_SL_BCH_CRC_LEN) != 0) {
|
||||
printf("Error in mib_sl crc check\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
memcpy(mib_sl, q->a, sizeof(uint8_t) * SRSLTE_SL_BCH_PAYLOAD_LEN);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void srslte_psbch_free(srslte_psbch_t* q)
|
||||
{
|
||||
if (q) {
|
||||
|
||||
srslte_dft_precoding_free(&q->dft_precoder);
|
||||
srslte_dft_precoding_free(&q->idft_precoder);
|
||||
srslte_viterbi_free(&q->dec);
|
||||
srslte_sequence_free(&q->seq);
|
||||
srslte_modem_table_free(&q->mod);
|
||||
|
||||
if (q->a) {
|
||||
free(q->a);
|
||||
}
|
||||
if (q->d) {
|
||||
free(q->d);
|
||||
}
|
||||
if (q->crc_temp) {
|
||||
free(q->crc_temp);
|
||||
}
|
||||
if (q->e) {
|
||||
free(q->e);
|
||||
}
|
||||
if (q->e_16) {
|
||||
free(q->e_16);
|
||||
}
|
||||
if (q->interleaver_lut) {
|
||||
free(q->interleaver_lut);
|
||||
}
|
||||
if (q->codeword) {
|
||||
free(q->codeword);
|
||||
}
|
||||
if (q->symbols) {
|
||||
free(q->symbols);
|
||||
}
|
||||
if (q->llr) {
|
||||
free(q->llr);
|
||||
}
|
||||
if (q->scfdma_symbols) {
|
||||
free(q->scfdma_symbols);
|
||||
}
|
||||
|
||||
bzero(q, sizeof(srslte_psbch_t));
|
||||
}
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <srslte/phy/utils/vector.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "srslte/phy/dft/ofdm.h"
|
||||
|
||||
#include "srslte/phy/io/filesource.h"
|
||||
|
||||
#include "srslte/phy/ch_estimation/chest_sl.h"
|
||||
#include "srslte/phy/phch/psbch.h"
|
||||
#include "srslte/phy/ue/ue_mib_sl.h"
|
||||
|
||||
#define SRSLTE_NSUBFRAMES_X_FRAME 10
|
||||
|
||||
char* input_file_name = NULL;
|
||||
srslte_cp_t cp = SRSLTE_CP_NORM;
|
||||
int sf_n_re, sf_n_samples, fft_size;
|
||||
uint32_t N_sl_id = 168, nof_prb = 25;
|
||||
bool use_standard_lte_rates = false;
|
||||
|
||||
void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [cdip]\n", prog);
|
||||
printf("\t-c n_sl_id [Default %d]\n", N_sl_id);
|
||||
printf("\t-d use_standard_lte_rates [Deafult %i]\n", use_standard_lte_rates);
|
||||
printf("\t-i input file (radio frame)\n");
|
||||
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
||||
}
|
||||
|
||||
void parse_args(int argc, char** argv)
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "cdip")) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
N_sl_id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
use_standard_lte_rates = true;
|
||||
break;
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'p':
|
||||
nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
parse_args(argc, argv);
|
||||
srslte_use_standard_symbol_size(use_standard_lte_rates);
|
||||
uint32_t symbol_sz = srslte_symbol_sz(nof_prb);
|
||||
printf("Symbol SZ: %i\n", symbol_sz);
|
||||
|
||||
sf_n_samples = symbol_sz * 15;
|
||||
fft_size = sf_n_samples * 2;
|
||||
sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * 12 * 2 * nof_prb;
|
||||
|
||||
int ret = SRSLTE_ERROR;
|
||||
|
||||
uint8_t* mib_sl_rx = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_MIB_SL_MAX_LEN);
|
||||
bzero(mib_sl_rx, sizeof(uint8_t) * SRSLTE_MIB_SL_MAX_LEN);
|
||||
|
||||
cf_t* sf_buffer_samples = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
bzero(sf_buffer_samples, sizeof(cf_t) * sf_n_samples);
|
||||
|
||||
cf_t* rx_re = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
bzero(rx_re, sizeof(cf_t) * sf_n_re);
|
||||
|
||||
cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
|
||||
|
||||
cf_t* equalized_sf = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
bzero(equalized_sf, sizeof(cf_t) * sf_n_re);
|
||||
|
||||
srslte_ofdm_t fft;
|
||||
if (srslte_ofdm_rx_init(&fft, SRSLTE_CP_NORM, sf_buffer_samples, rx_re, nof_prb)) {
|
||||
fprintf(stderr, "Error creating iFFT object\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_ofdm_set_normalize(&fft, true);
|
||||
srslte_ofdm_set_freq_shift(&fft, (float)-0.5);
|
||||
|
||||
srslte_ofdm_t ifft;
|
||||
if (srslte_ofdm_tx_init(&ifft, SRSLTE_CP_NORM, sf_buffer, sf_buffer_samples, nof_prb)) {
|
||||
fprintf(stderr, "Error creating iFFT object\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_ofdm_set_normalize(&ifft, true);
|
||||
srslte_ofdm_set_freq_shift(&ifft, 0.5);
|
||||
|
||||
srslte_psbch_t psbch;
|
||||
if (srslte_psbch_init(&psbch, N_sl_id, nof_prb)) {
|
||||
printf("Error creating PSBCH object\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
srslte_ue_mib_sl_t mib_sl;
|
||||
srslte_ue_mib_sl_set(&mib_sl, nof_prb, 0, 0, 0, false);
|
||||
|
||||
srslte_chest_sl_t psbch_est;
|
||||
srslte_chest_sl_init_psbch_dmrs(&psbch_est);
|
||||
srslte_chest_sl_gen_psbch_dmrs(&psbch_est, SRSLTE_SIDELINK_TM2, nof_prb, 0, N_sl_id);
|
||||
|
||||
if (!input_file_name) {
|
||||
// *************************************************************************************************************
|
||||
// PSBCH ENCODING
|
||||
// *************************************************************************************************************
|
||||
srslte_ue_mib_sl_pack(&mib_sl, psbch.a);
|
||||
srslte_psbch_encode(&psbch, psbch.a);
|
||||
|
||||
// Map PSBCH to subframe
|
||||
srslte_psbch_put(&psbch, sf_buffer);
|
||||
|
||||
// Map PSBCH DMRS to subframe
|
||||
srslte_chest_sl_put_psbch_dmrs(&psbch_est, sf_buffer, SRSLTE_SIDELINK_TM2, nof_prb);
|
||||
|
||||
// TS 36.211 Section 9.3.2: The last SC-FDMA symbol in a sidelink subframe serves as a guard period and shall not be
|
||||
// used for sidelink transmission.
|
||||
bzero(&sf_buffer[SRSLTE_NRE * nof_prb * (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * 2 - 1)],
|
||||
sizeof(cf_t) * SRSLTE_NRE * nof_prb);
|
||||
srslte_ofdm_tx_sf(&ifft);
|
||||
|
||||
} else {
|
||||
// *************************************************************************************************************
|
||||
// RADIO FRAME FROM MATLAB
|
||||
// *************************************************************************************************************
|
||||
srslte_filesource_t fsrc;
|
||||
if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) {
|
||||
printf("Error opening file %s\n", input_file_name);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
srslte_filesource_read(&fsrc, sf_buffer_samples, sf_n_samples);
|
||||
srslte_vec_sc_prod_cfc(sf_buffer_samples, sqrtf(symbol_sz), sf_buffer_samples, (uint32_t)sf_n_samples);
|
||||
|
||||
srslte_filesource_free(&fsrc);
|
||||
}
|
||||
|
||||
srslte_ofdm_rx_sf(&fft);
|
||||
// TS 36.211 Section 9.3.2: The last SC-FDMA symbol in a sidelink subframe serves as a guard period and shall not be
|
||||
// used for sidelink transmission.
|
||||
bzero(&rx_re[SRSLTE_NRE * nof_prb * (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * 2 - 1)], sizeof(cf_t) * SRSLTE_NRE * nof_prb);
|
||||
|
||||
srslte_chest_sl_psbch_ls_estimate_equalize(&psbch_est, rx_re, equalized_sf, nof_prb);
|
||||
|
||||
srslte_psbch_get(&psbch, equalized_sf);
|
||||
if (srslte_psbch_decode(&psbch, mib_sl_rx) == SRSLTE_SUCCESS) {
|
||||
printf("RX MIB-SL: ");
|
||||
for (int i = 0; i < SRSLTE_MIB_SL_MAX_LEN; ++i) {
|
||||
printf("%i", mib_sl_rx[i]);
|
||||
}
|
||||
printf("\n");
|
||||
ret = SRSLTE_SUCCESS;
|
||||
|
||||
srslte_ue_mib_sl_t rx_mib_sl;
|
||||
srlste_ue_mib_sl_unpack(&rx_mib_sl, mib_sl_rx);
|
||||
|
||||
printf("Bandwidth: %i\n", rx_mib_sl.sl_bandwidth_r12);
|
||||
printf("TDD Config: %i\n", rx_mib_sl.tdd_config_sl_r12);
|
||||
printf("Direct Frame Number: %i\n", rx_mib_sl.direct_frame_number_r12);
|
||||
printf("Direct Subframe Number: %i\n", rx_mib_sl.direct_subframe_number_r12);
|
||||
printf("In Coverage: %i\n", rx_mib_sl.in_coverage_r12);
|
||||
}
|
||||
|
||||
srslte_chest_sl_free(&psbch_est);
|
||||
|
||||
srslte_psbch_free(&psbch);
|
||||
srslte_ue_mib_sl_free(&mib_sl);
|
||||
|
||||
srslte_ofdm_rx_free(&fft);
|
||||
srslte_ofdm_tx_free(&ifft);
|
||||
|
||||
free(rx_re);
|
||||
free(mib_sl_rx);
|
||||
free(sf_buffer);
|
||||
free(equalized_sf);
|
||||
free(sf_buffer_samples);
|
||||
|
||||
printf(ret == SRSLTE_ERROR ? "FAILED\n" : "SUCCESS\n");
|
||||
|
||||
return ret;
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "srslte/phy/sync/psss.h"
|
||||
|
||||
#include "srslte/phy/dft/ofdm.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector_simd.h"
|
||||
#include <srslte/phy/utils/vector.h>
|
||||
|
||||
// Generates the sidelink sequences that are used to detect PSSS
|
||||
int srslte_psss_init(srslte_psss_t* q, uint32_t nof_prb, srslte_cp_t cp)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL) {
|
||||
|
||||
// Generate the 2 PSSS sequences
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
if (srslte_psss_generate(q->psss_signal[i], i) != SRSLTE_SUCCESS) {
|
||||
ERROR("Error srslte_psss_generate\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialization of buffers for find PSSS operations
|
||||
*/
|
||||
uint32_t sf_n_samples = srslte_symbol_sz(nof_prb) * 15;
|
||||
uint32_t fft_size = sf_n_samples * 2;
|
||||
|
||||
q->psss_sf_freq = srslte_vec_malloc(sizeof(cf_t*) * 2);
|
||||
if (!q->psss_sf_freq) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
q->psss_sf_freq[i] = srslte_vec_malloc(sizeof(cf_t) * fft_size);
|
||||
if (!q->psss_sf_freq[i]) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
q->input_pad_freq = srslte_vec_malloc(sizeof(cf_t) * fft_size);
|
||||
if (!q->input_pad_freq) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->input_pad_time = srslte_vec_malloc(sizeof(cf_t) * fft_size);
|
||||
if (!q->input_pad_time) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
srslte_ofdm_t psss_tx;
|
||||
if (srslte_ofdm_tx_init(&psss_tx, cp, q->input_pad_freq, q->input_pad_time, nof_prb)) {
|
||||
printf("Error creating iFFT object\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_ofdm_set_normalize(&psss_tx, true);
|
||||
srslte_ofdm_set_freq_shift(&psss_tx, 0.5);
|
||||
|
||||
srslte_dft_plan_t plan;
|
||||
if (srslte_dft_plan(&plan, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_dft_plan_set_norm(&plan, true);
|
||||
srslte_dft_plan_set_mirror(&plan, true);
|
||||
|
||||
// Create empty subframes with only PSSS
|
||||
for (uint32_t N_id_2 = 0; N_id_2 < 2; ++N_id_2) {
|
||||
bzero(q->input_pad_freq, sizeof(cf_t) * fft_size);
|
||||
bzero(q->input_pad_time, sizeof(cf_t) * fft_size);
|
||||
|
||||
srslte_psss_put_sf_buffer(q->psss_signal[N_id_2], q->input_pad_freq, nof_prb, cp);
|
||||
srslte_ofdm_tx_sf(&psss_tx);
|
||||
|
||||
srslte_dft_run_c(&plan, q->input_pad_time, q->psss_sf_freq[N_id_2]);
|
||||
srslte_vec_conj_cc(q->psss_sf_freq[N_id_2], q->psss_sf_freq[N_id_2], fft_size);
|
||||
}
|
||||
|
||||
srslte_dft_plan_free(&plan);
|
||||
srslte_ofdm_tx_free(&psss_tx);
|
||||
|
||||
q->dot_prod_output = srslte_vec_malloc(sizeof(cf_t) * fft_size);
|
||||
if (!q->dot_prod_output) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->dot_prod_output_time = srslte_vec_malloc(sizeof(cf_t) * fft_size);
|
||||
if (!q->dot_prod_output_time) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->shifted_output = srslte_vec_malloc(sizeof(cf_t) * fft_size);
|
||||
if (!q->shifted_output) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->shifted_output_abs = srslte_vec_malloc(sizeof(float) * fft_size);
|
||||
if (!q->shifted_output_abs) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_dft_plan(&q->plan_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_dft_plan_set_mirror(&q->plan_input, true);
|
||||
// srslte_dft_plan_set_dc(&psss->plan_input, true);
|
||||
srslte_dft_plan_set_norm(&q->plan_input, true);
|
||||
|
||||
if (srslte_dft_plan(&q->plan_out, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
// srslte_dft_plan_set_mirror(&psss->plan_out, true);
|
||||
srslte_dft_plan_set_dc(&q->plan_out, true);
|
||||
srslte_dft_plan_set_norm(&q->plan_out, true);
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates the Zadoff-Chu sequence.
|
||||
* @param signal Output array.
|
||||
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.7.1.1
|
||||
*/
|
||||
int srslte_psss_generate(cf_t* psss_signal, uint32_t N_id_2)
|
||||
{
|
||||
int i;
|
||||
float arg;
|
||||
int sign = -1;
|
||||
const float root_value[] = {26.0, 37.0};
|
||||
|
||||
if (N_id_2 > 1) {
|
||||
ERROR("Invalid N_id_2 %d\n", N_id_2);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < SRSLTE_PSSS_LEN / 2; i++) {
|
||||
arg = (float)sign * M_PI * root_value[N_id_2] * ((float)i * ((float)i + 1.0)) / 63.0;
|
||||
__real__ psss_signal[i] = cosf(arg);
|
||||
__imag__ psss_signal[i] = sinf(arg);
|
||||
}
|
||||
for (i = SRSLTE_PSSS_LEN / 2; i < SRSLTE_PSSS_LEN; i++) {
|
||||
arg = (float)sign * M_PI * root_value[N_id_2] * (((float)i + 2.0) * ((float)i + 1.0)) / 63.0;
|
||||
__real__ psss_signal[i] = cosf(arg);
|
||||
__imag__ psss_signal[i] = sinf(arg);
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping PSSS to resource elements
|
||||
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.7.1.2
|
||||
*/
|
||||
void srslte_psss_put_sf_buffer(cf_t* psss_signal, cf_t* sf_buffer, uint32_t nof_prb, srslte_cp_t cp)
|
||||
{
|
||||
// Normal cyclic prefix l = 1,2
|
||||
// Extended cyclic prefix l = 0,1
|
||||
for (int i = 0; i < 2; i++) {
|
||||
uint32_t k = (SRSLTE_CP_NSYMB(cp) - (5 + i)) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31;
|
||||
bzero(&sf_buffer[k - 5], sizeof(cf_t) * 5);
|
||||
memcpy(&sf_buffer[k], psss_signal, SRSLTE_PSSS_LEN * sizeof(cf_t));
|
||||
bzero(&sf_buffer[k + SRSLTE_PSSS_LEN], sizeof(cf_t) * 5);
|
||||
}
|
||||
}
|
||||
|
||||
/** Performs PSSS correlation.
|
||||
* Returns the index of the PSSS correlation peak in a subframe (corr_peak_pos).
|
||||
* The value of the correlation is stored in corr_peak_value.
|
||||
* The subframe starts at corr_peak_pos - sf_n_samples.
|
||||
*
|
||||
* * Input buffer must be subframe_size long.
|
||||
*/
|
||||
int srslte_psss_find(srslte_psss_t* q, cf_t* input, uint32_t nof_prb, srslte_cp_t cp)
|
||||
{
|
||||
// One array for each N_id_2
|
||||
float corr_peak_value[2] = {};
|
||||
uint32_t corr_peak_pos[2] = {};
|
||||
|
||||
uint32_t sf_n_samples = srslte_symbol_sz(nof_prb) * 15;
|
||||
uint32_t fft_size = sf_n_samples * 2;
|
||||
|
||||
bzero(q->input_pad_freq, sizeof(cf_t) * fft_size);
|
||||
bzero(q->input_pad_time, sizeof(cf_t) * fft_size);
|
||||
|
||||
memcpy(q->input_pad_time, input, sizeof(cf_t) * sf_n_samples);
|
||||
|
||||
srslte_dft_run_c(&q->plan_input, q->input_pad_time, q->input_pad_freq);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// .*
|
||||
srslte_vec_prod_ccc(q->psss_sf_freq[i], q->input_pad_freq, q->dot_prod_output, fft_size);
|
||||
|
||||
// IFFT
|
||||
srslte_dft_run_c(&q->plan_out, q->dot_prod_output, q->dot_prod_output_time);
|
||||
|
||||
bzero(q->shifted_output, sizeof(cf_t) * fft_size);
|
||||
memcpy(q->shifted_output, &q->dot_prod_output_time[fft_size / 2], sizeof(cf_t) * fft_size / 2);
|
||||
memcpy(&q->shifted_output[fft_size / 2], q->dot_prod_output_time, sizeof(cf_t) * fft_size / 2);
|
||||
|
||||
// Peak detection
|
||||
q->corr_peak_pos = -1;
|
||||
bzero(q->shifted_output_abs, sizeof(float) * fft_size);
|
||||
srslte_vec_abs_cf_simd(q->shifted_output, q->shifted_output_abs, fft_size);
|
||||
|
||||
// Experimental Validation
|
||||
int symbol_sz = srslte_symbol_sz(nof_prb);
|
||||
int cp_len = SRSLTE_CP_SZ(symbol_sz, cp);
|
||||
|
||||
// Correlation output peaks:
|
||||
//
|
||||
// |
|
||||
// | |
|
||||
// | |
|
||||
// | | | |
|
||||
// |...______________|____________|____________|______________... t (samples)
|
||||
// side peak main peak side peak
|
||||
|
||||
// Find the main peak
|
||||
q->corr_peak_pos = srslte_vec_max_fi(q->shifted_output_abs, fft_size);
|
||||
q->corr_peak_value = q->shifted_output_abs[q->corr_peak_pos];
|
||||
if ((q->corr_peak_pos < sf_n_samples) || (q->corr_peak_pos > fft_size - symbol_sz)) {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
bzero(&q->shifted_output_abs[q->corr_peak_pos - (symbol_sz / 2)], sizeof(float) * symbol_sz);
|
||||
|
||||
// Find the first side peak
|
||||
uint32_t peak_1_pos = srslte_vec_max_fi(q->shifted_output_abs, fft_size);
|
||||
float peak_1_value = q->shifted_output_abs[peak_1_pos];
|
||||
if ((peak_1_pos >= (q->corr_peak_pos - (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_1_pos <= (q->corr_peak_pos - (symbol_sz + cp_len) + 2))) {
|
||||
} else if ((peak_1_pos >= (q->corr_peak_pos + (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_1_pos <= (q->corr_peak_pos + (symbol_sz + cp_len) + 2))) {
|
||||
} else {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
bzero(&q->shifted_output_abs[peak_1_pos - (symbol_sz / 2)], sizeof(float) * symbol_sz);
|
||||
|
||||
// Find the second side peak
|
||||
uint32_t peak_2_pos = srslte_vec_max_fi(q->shifted_output_abs, fft_size);
|
||||
float peak_2_value = q->shifted_output_abs[peak_2_pos];
|
||||
if ((peak_2_pos >= (q->corr_peak_pos - (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_2_pos <= (q->corr_peak_pos - (symbol_sz + cp_len) + 2))) {
|
||||
} else if ((peak_2_pos >= (q->corr_peak_pos + (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_2_pos <= (q->corr_peak_pos + (symbol_sz + cp_len) + 2))) {
|
||||
} else {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
bzero(&q->shifted_output_abs[peak_2_pos - (symbol_sz / 2)], sizeof(float) * symbol_sz);
|
||||
|
||||
float threshold_above = q->corr_peak_value / 2.0 * 1.4;
|
||||
if ((peak_1_value > threshold_above) || (peak_2_value > threshold_above)) {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
float threshold_below = q->corr_peak_value / 2.0 * 0.6;
|
||||
if ((peak_1_value < threshold_below) || (peak_2_value < threshold_below)) {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
corr_peak_value[i] = q->corr_peak_value;
|
||||
corr_peak_pos[i] = q->corr_peak_pos;
|
||||
}
|
||||
|
||||
q->N_id_2 = srslte_vec_max_fi(corr_peak_value, 2);
|
||||
if (corr_peak_value[q->N_id_2] == 0.0) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->corr_peak_pos = corr_peak_pos[q->N_id_2];
|
||||
q->corr_peak_value = corr_peak_value[q->N_id_2];
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void srslte_psss_free(srslte_psss_t* q)
|
||||
{
|
||||
if (q) {
|
||||
srslte_dft_plan_free(&q->plan_out);
|
||||
srslte_dft_plan_free(&q->plan_input);
|
||||
|
||||
if (q->shifted_output) {
|
||||
free(q->shifted_output);
|
||||
}
|
||||
if (q->shifted_output_abs) {
|
||||
free(q->shifted_output_abs);
|
||||
}
|
||||
if (q->dot_prod_output) {
|
||||
free(q->dot_prod_output);
|
||||
}
|
||||
if (q->dot_prod_output_time) {
|
||||
free(q->dot_prod_output_time);
|
||||
}
|
||||
if (q->input_pad_freq) {
|
||||
free(q->input_pad_freq);
|
||||
}
|
||||
if (q->input_pad_time) {
|
||||
free(q->input_pad_time);
|
||||
}
|
||||
if (q->psss_sf_freq) {
|
||||
for (int N_id_2 = 0; N_id_2 < 2; ++N_id_2) {
|
||||
if (q->psss_sf_freq[N_id_2]) {
|
||||
free(q->psss_sf_freq[N_id_2]);
|
||||
}
|
||||
}
|
||||
free(q->psss_sf_freq);
|
||||
}
|
||||
|
||||
bzero(q, sizeof(srslte_psss_t));
|
||||
}
|
||||
}
|
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "srslte/phy/sync/ssss.h"
|
||||
|
||||
#include "gen_sss.c"
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/dft/ofdm.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
||||
// Generates the Sidelink sequences that are used to detect SSSS
|
||||
int srslte_ssss_init(srslte_ssss_t* q, uint32_t nof_prb, srslte_cp_t cp, srslte_sl_tm_t tm)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
if (q != NULL) {
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
uint32_t symbol_sz = srslte_symbol_sz(nof_prb);
|
||||
int cp_len = SRSLTE_CP_SZ(symbol_sz, cp);
|
||||
uint32_t sf_n_re = SRSLTE_CP_NSYMB(cp) * 12 * 2 * nof_prb;
|
||||
uint32_t sf_n_samples = symbol_sz * 15;
|
||||
|
||||
uint32_t ssss_n_samples =
|
||||
(symbol_sz + cp_len) * 2 +
|
||||
cp_len; // We need an extra cp_len in order to get the peaks centered after the correlation
|
||||
|
||||
// CP Normal: ssss (with its cp) starts at sample number: 11 symbol_sz + 2 CP_LEN_NORM_0 + 9 cp_len
|
||||
// CP Extended: ssss (with its cp) starts at sample number: 9 symbol_sz + 9 cp_len
|
||||
uint32_t ssss_start = (cp == SRSLTE_CP_NORM)
|
||||
? (symbol_sz * 11 + (SRSLTE_CP_LEN_NORM(0, symbol_sz) * 2 + cp_len * 9))
|
||||
: ((symbol_sz + cp_len) * 9);
|
||||
|
||||
for (int i = 0; i < SRSLTE_SSSS_NOF_SEQ; ++i) {
|
||||
srslte_ssss_generate(q->ssss_signal[i], i, tm);
|
||||
}
|
||||
|
||||
if (srslte_dft_plan(&q->plan_input, ssss_n_samples, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_dft_plan_set_mirror(&q->plan_input, true);
|
||||
srslte_dft_plan_set_norm(&q->plan_input, true);
|
||||
|
||||
q->input_pad_freq = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
if (!q->input_pad_freq) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->input_pad_time = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
if (!q->input_pad_time) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
srslte_ofdm_t ssss_ifft;
|
||||
if (srslte_ofdm_tx_init(&ssss_ifft, cp, q->input_pad_freq, q->input_pad_time, nof_prb)) {
|
||||
printf("Error creating iFFT object\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_ofdm_set_normalize(&ssss_ifft, true);
|
||||
srslte_ofdm_set_freq_shift(&ssss_ifft, 0.5);
|
||||
|
||||
q->ssss_sf_freq = srslte_vec_malloc(sizeof(cf_t*) * SRSLTE_SSSS_NOF_SEQ);
|
||||
if (!q->ssss_sf_freq) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
for (int i = 0; i < SRSLTE_SSSS_NOF_SEQ; ++i) {
|
||||
q->ssss_sf_freq[i] = srslte_vec_malloc(sizeof(cf_t) * ssss_n_samples);
|
||||
if (!q->ssss_sf_freq[i]) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < SRSLTE_SSSS_NOF_SEQ; ++i) {
|
||||
bzero(q->input_pad_freq, sizeof(cf_t) * ssss_n_samples);
|
||||
bzero(q->input_pad_time, sizeof(cf_t) * ssss_n_samples);
|
||||
bzero(q->ssss_sf_freq[i], sizeof(cf_t) * ssss_n_samples);
|
||||
|
||||
srslte_ssss_put_sf_buffer(q->ssss_signal[i], q->input_pad_freq, nof_prb, cp);
|
||||
srslte_ofdm_tx_sf(&ssss_ifft);
|
||||
|
||||
srslte_dft_run_c(&q->plan_input, &q->input_pad_time[ssss_start], q->ssss_sf_freq[i]);
|
||||
srslte_vec_conj_cc(q->ssss_sf_freq[i], q->ssss_sf_freq[i], ssss_n_samples);
|
||||
}
|
||||
|
||||
srslte_ofdm_tx_free(&ssss_ifft);
|
||||
|
||||
q->dot_prod_output = srslte_vec_malloc(sizeof(cf_t) * ssss_n_samples);
|
||||
if (!q->dot_prod_output) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->dot_prod_output_time = srslte_vec_malloc(sizeof(cf_t) * ssss_n_samples);
|
||||
if (!q->dot_prod_output_time) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->shifted_output = srslte_vec_malloc(sizeof(cf_t) * ssss_n_samples);
|
||||
if (!q->shifted_output) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
memset(q->shifted_output, 0, sizeof(cf_t) * ssss_n_samples);
|
||||
|
||||
q->shifted_output_abs = srslte_vec_malloc(sizeof(float) * ssss_n_samples);
|
||||
if (!q->shifted_output_abs) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
memset(q->shifted_output_abs, 0, sizeof(float) * ssss_n_samples);
|
||||
|
||||
if (srslte_dft_plan(&q->plan_out, ssss_n_samples, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_dft_plan_set_dc(&q->plan_out, true);
|
||||
srslte_dft_plan_set_norm(&q->plan_out, true);
|
||||
// srslte_dft_plan_set_mirror(&q->plan_out, true);
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.7.2.1
|
||||
*/
|
||||
void srslte_ssss_generate(float* ssss_signal, uint32_t N_sl_id, srslte_sl_tm_t tm)
|
||||
{
|
||||
uint32_t id1 = N_sl_id % 168;
|
||||
uint32_t id2 = N_sl_id / 168;
|
||||
uint32_t m0;
|
||||
uint32_t m1;
|
||||
int s_t[SRSLTE_SSSS_N], c_t[SRSLTE_SSSS_N], z_t[SRSLTE_SSSS_N];
|
||||
int s0[SRSLTE_SSSS_N], s1[SRSLTE_SSSS_N], c0[SRSLTE_SSSS_N], c1[SRSLTE_SSSS_N], z1_0[SRSLTE_SSSS_N],
|
||||
z1_1[SRSLTE_SSSS_N];
|
||||
|
||||
generate_m0m1(id1, &m0, &m1);
|
||||
generate_zsc_tilde(z_t, s_t, c_t);
|
||||
|
||||
generate_s(s0, s_t, m0);
|
||||
generate_s(s1, s_t, m1);
|
||||
|
||||
generate_c(c0, c_t, id2, 0);
|
||||
generate_c(c1, c_t, id2, 1);
|
||||
|
||||
generate_z(z1_0, z_t, m0);
|
||||
generate_z(z1_1, z_t, m1);
|
||||
|
||||
// Transmission mode 1 and 2 uses only "subframe 0 sequence" in two symbols on subframe 0 depending on cp
|
||||
// Transmission mode 3 and 4 uses only "subframe 5 sequence" in two symbols on subframe 0 depending on cp
|
||||
if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) {
|
||||
for (uint32_t i = 0; i < SRSLTE_SSSS_N; i++) {
|
||||
ssss_signal[2 * i] = (float)(s0[i] * c0[i]);
|
||||
ssss_signal[2 * i + 1] = (float)(s1[i] * c1[i] * z1_0[i]);
|
||||
}
|
||||
} else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
|
||||
for (uint32_t i = 0; i < SRSLTE_SSSS_N; i++) {
|
||||
ssss_signal[2 * i] = (float)(s1[i] * c0[i]);
|
||||
ssss_signal[2 * i + 1] = (float)(s0[i] * c1[i] * z1_1[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping SSSS to resource elements
|
||||
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.7.2.2
|
||||
*/
|
||||
void srslte_ssss_put_sf_buffer(float* ssss_signal, cf_t* sf_buffer, uint32_t nof_prb, srslte_cp_t cp)
|
||||
{
|
||||
// Normal cycle prefix l = 4,5
|
||||
// Extended cycle prefix l = 3,4
|
||||
uint32_t slot1_pos = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE * nof_prb;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
uint32_t k = (SRSLTE_CP_NSYMB(cp) - 3 + i) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31;
|
||||
bzero(&sf_buffer[slot1_pos + k - 5], sizeof(cf_t) * 5);
|
||||
for (int j = 0; j < SRSLTE_SSSS_LEN; j++) {
|
||||
__real__ sf_buffer[slot1_pos + k + j] = ssss_signal[j];
|
||||
__imag__ sf_buffer[slot1_pos + k + j] = 0;
|
||||
}
|
||||
bzero(&sf_buffer[slot1_pos + k + SRSLTE_SSSS_LEN], sizeof(cf_t) * 5);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs SSSS correlation.
|
||||
* Returns the index of the SSSS correlation peak in a subframe.
|
||||
* The subframe starts at corr_peak_pos-subframe_size.
|
||||
* The value of the correlation is stored in corr_peak_value.
|
||||
*
|
||||
*/
|
||||
int srslte_ssss_find(srslte_ssss_t* q, cf_t* input, uint32_t nof_prb, uint32_t N_id_2, srslte_cp_t cp)
|
||||
{
|
||||
// One array for each sequence
|
||||
float corr_peak_value[SRSLTE_SSSS_NOF_SEQ] = {};
|
||||
uint32_t corr_peak_pos[SRSLTE_SSSS_NOF_SEQ] = {};
|
||||
|
||||
uint32_t symbol_sz = srslte_symbol_sz(nof_prb);
|
||||
int cp_len = SRSLTE_CP_SZ(symbol_sz, cp);
|
||||
|
||||
uint32_t ssss_n_samples = (symbol_sz + cp_len) * 2 +
|
||||
cp_len; // We need an extra cp_len in order to get the peaks centered after the correlation
|
||||
|
||||
bzero(q->input_pad_freq, sizeof(cf_t) * ssss_n_samples);
|
||||
bzero(q->input_pad_time, sizeof(cf_t) * ssss_n_samples);
|
||||
|
||||
// CP Normal: ssss (with its cp) starts at sample number: 11 symbol_sz + 2 CP_LEN_NORM_0 + 9 cp_len
|
||||
// CP Extended: ssss (with its cp) starts at sample number: 9 symbol_sz + 9 cp_len
|
||||
uint32_t ssss_start = (cp == SRSLTE_CP_NORM) ? (symbol_sz * 11 + (SRSLTE_CP_LEN_NORM(0, symbol_sz) * 2 + cp_len * 9))
|
||||
: ((symbol_sz + cp_len) * 9);
|
||||
|
||||
memcpy(q->input_pad_time, &input[ssss_start], sizeof(cf_t) * ssss_n_samples);
|
||||
|
||||
srslte_dft_run_c(&q->plan_input, q->input_pad_time, q->input_pad_freq);
|
||||
|
||||
// 0-167 or 168-335
|
||||
for (int i = (168 * N_id_2); i < (168 * (N_id_2 + 1)); i++) {
|
||||
srslte_vec_prod_ccc(q->ssss_sf_freq[i], q->input_pad_freq, q->dot_prod_output, ssss_n_samples);
|
||||
|
||||
srslte_dft_run_c(&q->plan_out, q->dot_prod_output, q->dot_prod_output_time);
|
||||
|
||||
memcpy(q->shifted_output, &q->dot_prod_output_time[ssss_n_samples / 2], sizeof(cf_t) * ssss_n_samples / 2);
|
||||
memcpy(&q->shifted_output[ssss_n_samples / 2], q->dot_prod_output_time, sizeof(cf_t) * ssss_n_samples / 2);
|
||||
|
||||
q->corr_peak_pos = -1;
|
||||
srslte_vec_abs_square_cf(q->shifted_output, q->shifted_output_abs, ssss_n_samples);
|
||||
|
||||
// Correlation output peaks:
|
||||
//
|
||||
// |
|
||||
// | |
|
||||
// | |
|
||||
// | | | |
|
||||
// |...______________|____________|____________|______________... t (samples)
|
||||
// side peak main peak side peak
|
||||
|
||||
// Find the main peak
|
||||
q->corr_peak_pos = srslte_vec_max_fi(q->shifted_output_abs, ssss_n_samples);
|
||||
q->corr_peak_value = q->shifted_output_abs[q->corr_peak_pos];
|
||||
if ((q->corr_peak_pos < ssss_n_samples / 2) || (q->corr_peak_pos > ssss_n_samples / 2)) {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
bzero(&q->shifted_output_abs[q->corr_peak_pos - (symbol_sz / 2)], sizeof(float) * symbol_sz);
|
||||
|
||||
// Find the first side peak
|
||||
uint32_t peak_1_pos = srslte_vec_max_fi(q->shifted_output_abs, ssss_n_samples);
|
||||
float peak_1_value = q->shifted_output_abs[peak_1_pos];
|
||||
if ((peak_1_pos >= (q->corr_peak_pos - (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_1_pos <= (q->corr_peak_pos - (symbol_sz + cp_len) + 2))) {
|
||||
} else if ((peak_1_pos >= (q->corr_peak_pos + (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_1_pos <= (q->corr_peak_pos + (symbol_sz + cp_len) + 2))) {
|
||||
} else {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
bzero(&q->shifted_output_abs[peak_1_pos - ((cp_len - 2) / 2)], sizeof(float) * (cp_len - 2));
|
||||
|
||||
// Find the second side peak
|
||||
uint32_t peak_2_pos = srslte_vec_max_fi(q->shifted_output_abs, ssss_n_samples);
|
||||
float peak_2_value = q->shifted_output_abs[peak_2_pos];
|
||||
if ((peak_2_pos >= (q->corr_peak_pos - (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_2_pos <= (q->corr_peak_pos - (symbol_sz + cp_len) + 2))) {
|
||||
} else if ((peak_2_pos >= (q->corr_peak_pos + (symbol_sz + cp_len) - 2)) &&
|
||||
(peak_2_pos <= (q->corr_peak_pos + (symbol_sz + cp_len) + 2))) {
|
||||
} else {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
bzero(&q->shifted_output_abs[peak_2_pos - ((cp_len - 2) / 2)], sizeof(float) * (cp_len - 2));
|
||||
|
||||
float threshold_above = q->corr_peak_value / 2.0 * 1.6;
|
||||
if ((peak_1_value > threshold_above) || (peak_2_value > threshold_above)) {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
float threshold_below = q->corr_peak_value / 2.0 * 0.4;
|
||||
if ((peak_1_value < threshold_below) || (peak_2_value < threshold_below)) {
|
||||
q->corr_peak_pos = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
corr_peak_value[i] = q->corr_peak_value;
|
||||
corr_peak_pos[i] = q->corr_peak_pos;
|
||||
}
|
||||
|
||||
q->N_sl_id = srslte_vec_max_fi(corr_peak_value, SRSLTE_SSSS_NOF_SEQ);
|
||||
if (corr_peak_value[q->N_sl_id] == 0.0) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->corr_peak_pos = corr_peak_pos[q->N_sl_id];
|
||||
q->corr_peak_value = corr_peak_value[q->N_sl_id];
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void srslte_ssss_free(srslte_ssss_t* q)
|
||||
{
|
||||
if (q) {
|
||||
srslte_dft_plan_free(&q->plan_input);
|
||||
srslte_dft_plan_free(&q->plan_out);
|
||||
if (q->shifted_output) {
|
||||
free(q->shifted_output);
|
||||
}
|
||||
if (q->shifted_output_abs) {
|
||||
free(q->shifted_output_abs);
|
||||
}
|
||||
if (q->dot_prod_output) {
|
||||
free(q->dot_prod_output);
|
||||
}
|
||||
if (q->dot_prod_output_time) {
|
||||
free(q->dot_prod_output_time);
|
||||
}
|
||||
if (q->input_pad_freq) {
|
||||
free(q->input_pad_freq);
|
||||
}
|
||||
if (q->input_pad_time) {
|
||||
free(q->input_pad_time);
|
||||
}
|
||||
if (q->ssss_sf_freq) {
|
||||
for (int N_sl_id = 0; N_sl_id < SRSLTE_SSSS_NOF_SEQ; ++N_sl_id) {
|
||||
if (q->ssss_sf_freq[N_sl_id]) {
|
||||
free(q->ssss_sf_freq[N_sl_id]);
|
||||
}
|
||||
}
|
||||
free(q->ssss_sf_freq);
|
||||
}
|
||||
|
||||
bzero(q, sizeof(srslte_ssss_t));
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "srslte/phy/sync/psss.h"
|
||||
#include "srslte/phy/sync/ssss.h"
|
||||
#include "srslte/srslte.h"
|
||||
|
||||
char* input_file_name;
|
||||
// int32_t N_sl_id = 168;
|
||||
// uint32_t offset = 0;
|
||||
float frequency_offset = 0.0;
|
||||
float snr = 100.0;
|
||||
srslte_cp_t cp = SRSLTE_CP_NORM;
|
||||
uint32_t nof_prb = 6;
|
||||
bool use_standard_lte_rates = false;
|
||||
srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2;
|
||||
uint32_t max_subframes = 10;
|
||||
|
||||
srslte_filesource_t fsrc;
|
||||
|
||||
void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [cdefiopstv]\n", prog);
|
||||
printf("\t-i input_file_name\n");
|
||||
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-e extended CP [Default normal]\n");
|
||||
printf("\t-m max_subframes [Default %d]\n", max_subframes);
|
||||
printf("\t-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (tm + 1));
|
||||
printf("\t-d use_standard_lte_rates [Default %i]\n", use_standard_lte_rates);
|
||||
printf("\t-v srslte_verbose\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char** argv)
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "cdefimpstv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
use_standard_lte_rates = true;
|
||||
break;
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'm':
|
||||
max_subframes = strtoul(argv[optind], NULL, 0);
|
||||
break;
|
||||
case 'p':
|
||||
nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
snr = atof(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
switch (atoi(argv[optind])) {
|
||||
case 1:
|
||||
tm = SRSLTE_SIDELINK_TM1;
|
||||
break;
|
||||
case 2:
|
||||
tm = SRSLTE_SIDELINK_TM2;
|
||||
break;
|
||||
case 3:
|
||||
tm = SRSLTE_SIDELINK_TM3;
|
||||
break;
|
||||
case 4:
|
||||
tm = SRSLTE_SIDELINK_TM4;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
parse_args(argc, argv);
|
||||
srslte_use_standard_symbol_size(use_standard_lte_rates);
|
||||
|
||||
if (!input_file_name || srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) {
|
||||
printf("Error opening file %s\n", input_file_name);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// alloc memory
|
||||
uint32_t sf_n_samples = SRSLTE_SF_LEN_PRB(nof_prb);
|
||||
printf("I/Q samples per subframe=%d\n", sf_n_samples);
|
||||
|
||||
uint32_t sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * 2 * nof_prb;
|
||||
cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
|
||||
cf_t* input_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
cf_t* input_buffer_temp = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
|
||||
// init PSSS
|
||||
srslte_psss_t psss;
|
||||
srslte_psss_init(&psss, nof_prb, cp);
|
||||
|
||||
struct timeval t[3];
|
||||
gettimeofday(&t[1], NULL);
|
||||
|
||||
bool sync = false;
|
||||
uint32_t num_subframes = 0;
|
||||
int32_t samples_read = 0;
|
||||
|
||||
do {
|
||||
// Read and normalize samples from file
|
||||
samples_read = srslte_filesource_read(&fsrc, input_buffer, sf_n_samples);
|
||||
if (samples_read == 0) {
|
||||
// read entire file
|
||||
break;
|
||||
} else if (samples_read != sf_n_samples) {
|
||||
printf("Could only read %d of %d requested samples\n", samples_read, sf_n_samples);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Find PSSS signal
|
||||
if (srslte_psss_find(&psss, input_buffer, nof_prb, cp) == SRSLTE_SUCCESS) {
|
||||
printf("PSSS correlation peak pos: %d value: %f N_id_2: %d\n",
|
||||
psss.corr_peak_pos,
|
||||
psss.corr_peak_value,
|
||||
psss.N_id_2);
|
||||
sync = true;
|
||||
}
|
||||
num_subframes++;
|
||||
} while (samples_read == sf_n_samples && num_subframes < max_subframes);
|
||||
|
||||
srslte_filesource_free(&fsrc);
|
||||
srslte_psss_free(&psss);
|
||||
free(input_buffer);
|
||||
free(input_buffer_temp);
|
||||
free(sf_buffer);
|
||||
|
||||
return (sync == SRSLTE_SUCCESS);
|
||||
}
|
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "srslte/phy/sync/psss.h"
|
||||
#include "srslte/phy/sync/ssss.h"
|
||||
#include "srslte/srslte.h"
|
||||
|
||||
char* input_file_name;
|
||||
int32_t N_sl_id = 168;
|
||||
uint32_t offset = 0;
|
||||
float frequency_offset = 0.0;
|
||||
float snr = 100.0;
|
||||
srslte_cp_t cp = SRSLTE_CP_NORM;
|
||||
uint32_t nof_prb = 6;
|
||||
bool use_standard_lte_rates = false;
|
||||
srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2;
|
||||
|
||||
srslte_filesource_t fsrc;
|
||||
|
||||
void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [cdefiopstv]\n", prog);
|
||||
printf("\t-i input_file_name\n");
|
||||
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-o offset [Default %d]\n", offset);
|
||||
printf("\t-e extended CP [Default normal]\n");
|
||||
printf("\t-d use_standard_lte_rates [Default %i]\n", use_standard_lte_rates);
|
||||
printf("\t-v srslte_verbose\n");
|
||||
printf("\nSelf-tests only:\n");
|
||||
printf("\t-c N_sl_id [Default %d]\n", N_sl_id);
|
||||
printf("\t-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (tm + 1));
|
||||
printf("\t-f frequency_offset [Default %.3f]\n", frequency_offset);
|
||||
printf("\t-s snr [Default %.3f]\n", snr);
|
||||
}
|
||||
|
||||
void parse_args(int argc, char** argv)
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "cdefiopstv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
N_sl_id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
use_standard_lte_rates = true;
|
||||
break;
|
||||
case 'e':
|
||||
cp = SRSLTE_CP_EXT;
|
||||
break;
|
||||
case 'f':
|
||||
frequency_offset = atof(argv[optind]);
|
||||
break;
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'o':
|
||||
offset = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
snr = atof(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
switch (atoi(argv[optind])) {
|
||||
case 1:
|
||||
tm = SRSLTE_SIDELINK_TM1;
|
||||
break;
|
||||
case 2:
|
||||
tm = SRSLTE_SIDELINK_TM2;
|
||||
break;
|
||||
case 3:
|
||||
tm = SRSLTE_SIDELINK_TM3;
|
||||
break;
|
||||
case 4:
|
||||
tm = SRSLTE_SIDELINK_TM4;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
||||
parse_args(argc, argv);
|
||||
srslte_use_standard_symbol_size(use_standard_lte_rates);
|
||||
|
||||
int32_t symbol_sz = srslte_symbol_sz(nof_prb);
|
||||
printf("Symbol SZ: %i\n", symbol_sz);
|
||||
|
||||
uint32_t sf_n_samples = srslte_symbol_sz(nof_prb) * 15;
|
||||
printf("sf_n_samples: %i\n", sf_n_samples);
|
||||
|
||||
uint32_t sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * 2 * nof_prb;
|
||||
cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
|
||||
cf_t* input_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
cf_t* input_buffer_temp = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
|
||||
uint32_t output_buffer_len = 0;
|
||||
cf_t* output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
|
||||
srslte_ofdm_t ifft;
|
||||
if (srslte_ofdm_tx_init(&ifft, cp, sf_buffer, output_buffer, nof_prb)) {
|
||||
ERROR("Error creating IFFT object\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_ofdm_set_normalize(&ifft, true);
|
||||
srslte_ofdm_set_freq_shift(&ifft, 0.5);
|
||||
|
||||
srslte_psss_t psss;
|
||||
srslte_psss_init(&psss, nof_prb, cp);
|
||||
|
||||
srslte_ssss_t ssss;
|
||||
srslte_ssss_init(&ssss, nof_prb, cp, tm);
|
||||
|
||||
if (input_file_name) {
|
||||
if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) {
|
||||
printf("Error opening file %s\n", input_file_name);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
} else {
|
||||
// Self-test with a single subframe (but can be extended to a radio frame or a PSCCH Period)
|
||||
|
||||
bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
|
||||
|
||||
srslte_psss_put_sf_buffer(psss.psss_signal[((N_sl_id < 168) ? 0 : 1)], sf_buffer, nof_prb, cp);
|
||||
srslte_ssss_put_sf_buffer(ssss.ssss_signal[N_sl_id], sf_buffer, nof_prb, cp);
|
||||
|
||||
// TS 36.211 Section 9.3.2: The last SC-FDMA symbol in a sidelink subframe serves as a guard period and shall
|
||||
// not be used for sidelink transmission.
|
||||
bzero(&sf_buffer[SRSLTE_NRE * nof_prb * (SRSLTE_CP_NSYMB(cp) * 2 - 1)], sizeof(cf_t) * SRSLTE_NRE * nof_prb);
|
||||
srslte_ofdm_tx_sf(&ifft);
|
||||
|
||||
output_buffer_len = sf_n_samples;
|
||||
|
||||
// ADD CHANNEL NOISE
|
||||
if (snr < 50) {
|
||||
float std_dev = powf(10.0f, -(snr + 3.0f) / 20.0f);
|
||||
srslte_ch_awgn_c(output_buffer, output_buffer, std_dev, output_buffer_len);
|
||||
}
|
||||
|
||||
// ADD FREQUENCY OFFSET
|
||||
if (frequency_offset != 0) {
|
||||
for (uint32_t i = 0; i < output_buffer_len; i++) {
|
||||
output_buffer[i] = output_buffer[i] * cexpf(I * (float)(2 * M_PI / (symbol_sz * 15e3)) * frequency_offset * i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int search_window_size = sf_n_samples - (2 * (symbol_sz + SRSLTE_CP_SZ(symbol_sz, cp)));
|
||||
|
||||
int32_t samples_read = 0;
|
||||
uint32_t samples_to_read;
|
||||
uint32_t offset_pos = 0;
|
||||
uint32_t output_buffer_pos = 0;
|
||||
|
||||
struct timeval t[3];
|
||||
gettimeofday(&t[1], NULL);
|
||||
|
||||
bool sync = false;
|
||||
|
||||
while (sync == false) {
|
||||
|
||||
samples_to_read = sf_n_samples - offset_pos;
|
||||
|
||||
if (offset < samples_to_read) {
|
||||
bzero(input_buffer, sizeof(cf_t) * offset);
|
||||
samples_to_read = sf_n_samples - offset_pos - offset;
|
||||
|
||||
if (input_file_name) {
|
||||
// Read and normalize samples from file
|
||||
samples_read = srslte_filesource_read(&fsrc, &input_buffer[offset + offset_pos], samples_to_read);
|
||||
// Normalization factor for third party input files
|
||||
srslte_vec_sc_prod_cfc(
|
||||
&input_buffer[offset + offset_pos], sqrtf(symbol_sz), &input_buffer[offset + offset_pos], samples_read);
|
||||
} else {
|
||||
// Self-test
|
||||
if ((output_buffer_len - output_buffer_pos) >= samples_to_read) {
|
||||
memcpy(&input_buffer[offset + offset_pos], &output_buffer[output_buffer_pos], sizeof(cf_t) * samples_to_read);
|
||||
samples_read = samples_to_read;
|
||||
output_buffer_pos += samples_read;
|
||||
} else {
|
||||
samples_read = 0;
|
||||
}
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
} else {
|
||||
samples_read = samples_to_read;
|
||||
offset = offset - samples_read;
|
||||
bzero(input_buffer, sizeof(cf_t) * samples_read);
|
||||
}
|
||||
|
||||
if (samples_read != samples_to_read) {
|
||||
printf("Couldn't read %i samples\n", samples_to_read);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Find sync signals
|
||||
if (srslte_psss_find(&psss, input_buffer, nof_prb, cp) == SRSLTE_SUCCESS) {
|
||||
|
||||
printf("PSSS correlation peak pos: %d value: %f N_id_2: %d\n",
|
||||
psss.corr_peak_pos,
|
||||
psss.corr_peak_value,
|
||||
psss.N_id_2);
|
||||
|
||||
if (psss.corr_peak_pos - sf_n_samples == 0) {
|
||||
// Find SSSS
|
||||
if (srslte_ssss_find(&ssss, input_buffer, nof_prb, psss.N_id_2, cp) == SRSLTE_SUCCESS) {
|
||||
|
||||
printf("SSSS correlation peak pos: %d value: %f N_sl_id: %d \n",
|
||||
ssss.corr_peak_pos,
|
||||
ssss.corr_peak_value,
|
||||
ssss.N_sl_id);
|
||||
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
printf("\nSLSS found with N_sl_id: %d (in %.0f usec)\n\n",
|
||||
ssss.N_sl_id,
|
||||
(int)t[0].tv_sec * 1e6 + (int)t[0].tv_usec);
|
||||
|
||||
sync = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Sample offset correction
|
||||
offset_pos = sf_n_samples - (psss.corr_peak_pos - sf_n_samples);
|
||||
memcpy(input_buffer_temp, &input_buffer[sf_n_samples - offset_pos], sizeof(cf_t) * offset_pos);
|
||||
memcpy(input_buffer, input_buffer_temp, sizeof(cf_t) * offset_pos);
|
||||
}
|
||||
} else {
|
||||
// Next search window
|
||||
offset_pos = sf_n_samples - search_window_size;
|
||||
memcpy(input_buffer_temp, &input_buffer[sf_n_samples - offset_pos], sizeof(cf_t) * offset_pos);
|
||||
memcpy(input_buffer, input_buffer_temp, sizeof(cf_t) * offset_pos);
|
||||
}
|
||||
}
|
||||
|
||||
srslte_filesource_free(&fsrc);
|
||||
srslte_ofdm_tx_free(&ifft);
|
||||
srslte_ssss_free(&ssss);
|
||||
srslte_psss_free(&psss);
|
||||
free(input_buffer);
|
||||
free(input_buffer_temp);
|
||||
free(sf_buffer);
|
||||
free(output_buffer);
|
||||
|
||||
if (sync) {
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
return SRSLTE_ERROR;
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* srsLTE 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.
|
||||
*
|
||||
* A copy of the GNU Affero 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 <srslte/config.h>
|
||||
#include <srslte/phy/utils/bit.h>
|
||||
#include <srslte/phy/utils/vector.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <srslte/phy/ue/ue_mib_sl.h>
|
||||
#include <srslte/phy/utils/debug.h>
|
||||
|
||||
int srslte_ue_mib_sl_set(srslte_ue_mib_sl_t* q,
|
||||
uint32_t nof_prb,
|
||||
uint32_t tdd_config,
|
||||
uint32_t direct_frame_number,
|
||||
uint32_t direct_subframe_number,
|
||||
bool in_coverage)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
if (q != NULL) {
|
||||
|
||||
switch (nof_prb) {
|
||||
case 6:
|
||||
q->sl_bandwidth_r12 = 0;
|
||||
break;
|
||||
case 15:
|
||||
q->sl_bandwidth_r12 = 1;
|
||||
break;
|
||||
case 25:
|
||||
q->sl_bandwidth_r12 = 2;
|
||||
break;
|
||||
case 50:
|
||||
q->sl_bandwidth_r12 = 3;
|
||||
break;
|
||||
case 75:
|
||||
q->sl_bandwidth_r12 = 4;
|
||||
break;
|
||||
case 100:
|
||||
q->sl_bandwidth_r12 = 5;
|
||||
break;
|
||||
default:
|
||||
printf("Invalid bandwidth\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->tdd_config_sl_r12 = tdd_config;
|
||||
q->direct_frame_number_r12 = direct_frame_number;
|
||||
q->direct_subframe_number_r12 = direct_subframe_number;
|
||||
q->in_coverage_r12 = in_coverage;
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void srslte_ue_mib_sl_pack(srslte_ue_mib_sl_t *q, uint8_t *msg)
|
||||
{
|
||||
bzero(msg, sizeof(uint8_t) * SRSLTE_MIB_SL_MAX_LEN);
|
||||
srslte_bit_unpack(q->sl_bandwidth_r12, &msg, 3);
|
||||
srslte_bit_unpack(q->tdd_config_sl_r12, &msg, 3);
|
||||
srslte_bit_unpack(q->direct_frame_number_r12, &msg, 10);
|
||||
srslte_bit_unpack(q->direct_subframe_number_r12, &msg, 4);
|
||||
srslte_bit_unpack((uint32_t)q->in_coverage_r12, &msg, 1);
|
||||
}
|
||||
|
||||
void srlste_ue_mib_sl_unpack(srslte_ue_mib_sl_t *q, uint8_t *msg)
|
||||
{
|
||||
q->sl_bandwidth_r12 = srslte_bit_pack(&msg, 3);
|
||||
q->tdd_config_sl_r12 = srslte_bit_pack(&msg, 3);
|
||||
q->direct_frame_number_r12 = srslte_bit_pack(&msg, 10);
|
||||
q->direct_subframe_number_r12 = srslte_bit_pack(&msg, 4);
|
||||
q->in_coverage_r12 = (bool)srslte_bit_pack(&msg, 1);
|
||||
}
|
||||
|
||||
void srslte_ue_mib_sl_free(srslte_ue_mib_sl_t* q)
|
||||
{
|
||||
if (q != NULL) {
|
||||
bzero(q, sizeof(srslte_ue_mib_sl_t));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue