PSSS and SSSS implementation

This commit is contained in:
Tiago Ferreira Alves 2019-10-11 11:10:07 +01:00 committed by Andre Puschmann
parent 476f970ee1
commit 3fed21ce3e
28 changed files with 2853 additions and 2 deletions

View File

@ -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

View File

@ -288,7 +288,7 @@ enum band_geographical_area {
SRSLTE_BAND_GEO_AREA_NA
};
// NB-IoT specific structs
///< NB-IoT specific structs
typedef enum {
SRSLTE_NBIOT_MODE_INBAND_SAME_PCI = 0,
SRSLTE_NBIOT_MODE_INBAND_DIFFERENT_PCI,
@ -329,6 +329,21 @@ typedef struct SRSLTE_API {
#define SRSLTE_NBIOT_NPBCH_NOF_BITS_SF \
(SRSLTE_NBIOT_NPBCH_NOF_TOTAL_BITS / 8) ///< The NPBCH is transmitted in 8 blocks (See 36.211 Sec 10.2.4.4)
///< Sidelink
typedef enum SRSLTE_API {
SRSLTE_SIDELINK_TM1,
SRSLTE_SIDELINK_TM2,
SRSLTE_SIDELINK_TM3,
SRSLTE_SIDELINK_TM4
} srslte_sl_tm_t;
typedef enum SRSLTE_API {
SRSLTE_SIDELINK_PSBCH,
SRSLTE_SIDELINK_PSCCH,
SRSLTE_SIDELINK_PSSCH,
SRSLTE_SIDELINK_PSDCH
} srslte_sl_channels_t;
SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t* cell);
SRSLTE_API void srslte_cell_fprint(FILE* stream, srslte_cell_t* cell, uint32_t sfn);

View File

@ -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

View File

@ -59,4 +59,6 @@ SRSLTE_API void srslte_cfo_correct(srslte_cfo_t* h, const cf_t* input, cf_t* out
SRSLTE_API void
srslte_cfo_correct_offset(srslte_cfo_t* h, const cf_t* input, cf_t* output, float freq, int cexp_offset, int nsamples);
SRSLTE_API float srslte_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb);
#endif // SRSLTE_CFO_H

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

359
lib/src/phy/phch/psbch.c Normal file
View File

@ -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));
}
}

View File

@ -30,7 +30,26 @@ add_test(pbch_test_62 pbch_test -p 2 -n 6 -c 100)
add_test(pbch_test_64 pbch_test -p 4 -n 6 -c 100)
add_test(pbch_test_50 pbch_test -p 1 -n 50 -c 50)
add_test(pbch_test_502 pbch_test -p 2 -n 50 -c 50)
add_test(pbch_test_504 pbch_test -p 4 -n 50 -c 50)
add_test(pbch_test_504 pbch_test -p 4 -n 50 -c 50)
########################################################################
# PSBCH TEST
########################################################################
add_executable(psbch_test psbch_test.c)
target_link_libraries(psbch_test srslte_phy)
# TM2 self tests
add_test(psbch_test_self_test_tm2_p6_c168_self psbch_test -p 6 -c 168 -d)
add_test(psbch_test_self_test_tm2_p25_c168_self psbch_test -p 25 -c 168 -d)
add_test(psbch_test_self_test_tm2_p100_c168_self psbch_test -p 100 -c 168 -d)
# TM2 file tests
add_test(psbch_file_test_ideal_tm2_p6_c0 psbch_test -p 6 -c 0 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e+6.dat)
add_test(psbch_file_test_ideal_tm2_p15_c84 psbch_test -p 15 -c 84 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e+6.dat)
add_test(psbch_file_test_ideal_tm2_p25_c168 psbch_test -p 25 -c 168 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat)
add_test(psbch_file_test_ideal_tm2_p50_c252 psbch_test -p 50 -c 252 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e+6.dat)
add_test(psbch_file_test_ideal_tm2_p100_c335 psbch_test -p 100 -c 335 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e+6.dat)
########################################################################
# NPBCH TEST

View File

@ -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;
}

View File

@ -125,4 +125,25 @@ void srslte_cfo_correct_offset(srslte_cfo_t* h,
DEBUG("CFO generating new table for frequency %.4fe-6\n", freq * 1e6);
}
srslte_vec_prod_ccc(&h->cur_cexp[cexp_offset], input, output, nsamples);
}
float srslte_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb)
{
int nFFT = srslte_symbol_sz(nof_prb);
int sf_n_samples = nFFT * 15;
float tFFT = (float)(1 / 15000.0);
int cp_size = SRSLTE_CP_LEN_NORM(1, nFFT);
// Compensate for initial SC-FDMA half subcarrier shift
srslte_vec_apply_cfo(input_buffer, (float)(1 / (nFFT * 15e3)) * (15e3 / 2.0), input_buffer, sf_n_samples);
// Conjugate multiply the correlation inputs
cf_t cfo_estimated = srslte_vec_dot_prod_conj_ccc(&input_buffer[nFFT + SRSLTE_CP_LEN_NORM(0, nFFT)],
&input_buffer[2 * nFFT + SRSLTE_CP_LEN_NORM(0, nFFT)],
cp_size);
// CFO correction and compensation for initial SC-FDMA half subcarrier shift
float cfo = (float)(-1 * carg(cfo_estimated) / (float)(2 * M_PI * tFFT));
srslte_vec_apply_cfo(input_buffer, (float)(1 / (nFFT * 15e3)) * ((-15e3 / 2.0) - cfo), input_buffer, sf_n_samples);
return cfo;
}

336
lib/src/phy/sync/psss.c Normal file
View File

@ -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));
}
}

351
lib/src/phy/sync/ssss.c Normal file
View File

@ -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));
}
}

View File

@ -76,10 +76,54 @@ add_test(sync_test_400 sync_test -o 400 -p 50 -c 500)
add_test(sync_test_100_e sync_test -o 100 -e -p 50 -c 133)
add_test(sync_test_400_e sync_test -o 400 -e -p 50 -c 123)
########################################################################
# SYNC NB-IoT TEST
########################################################################
add_test(npss_test_nonoise npss_test)
add_test(nsss_test_nonoise_2 nsss_test -c 2)
add_test(nsss_test_nonoise_501 nsss_test -c 501)
########################################################################
# SYNC SL TEST
########################################################################
add_executable(sync_sl_test sync_sl_test.c)
target_link_libraries(sync_sl_test srslte_phy)
add_executable(psss_file_test psss_file_test.c)
target_link_libraries(psss_file_test srslte_phy)
# SL TM 2
add_test(sync_sl_test_tm2_p6_c_0 sync_sl_test -p 6 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e+6.dat)
add_test(sync_sl_test_tm2_p15_c_84 sync_sl_test -p 15 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e+6.dat)
add_test(sync_sl_test_tm2_p25_c_168 sync_sl_test -p 25 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat)
add_test(sync_sl_test_tm2_p50_c_252 sync_sl_test -p 50 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e+6.dat)
add_test(sync_sl_test_tm2_p100_c_335 sync_sl_test -p 100 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e+6.dat)
# Sample offset
add_test(sync_sl_test_tm2_p25_c_168_so sync_sl_test -p 25 -d -o 300 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat)
# Self-test
add_test(sync_sl_test_tm2_self_test_p25_c_168 sync_sl_test -p 25 -c 168 -d)
# Self-test with frequency offset
add_test(sync_sl_test_tm2_self_test_p25_c_168_fo sync_sl_test -p 25 -c 168 -d -f 100)
# Self-test with frequency offset and sample offset
add_test(sync_sl_test_tm2_self_test_p25_c_168_fo_so sync_sl_test -p 25 -c 168 -d -f 100 -o 3600)
# SL TM 4
add_test(sync_sl_test_tm4_p6_c_0 sync_sl_test -p 6 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_s1.92e+6.dat)
add_test(sync_sl_test_tm4_p15_c_84 sync_sl_test -p 15 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_s3.84e+6.dat)
add_test(sync_sl_test_tm4_p25_c_168 sync_sl_test -p 25 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_s7.68e+6.dat)
add_test(sync_sl_test_tm4_p50_c_252 sync_sl_test -p 50 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_s15.36e+6.dat)
add_test(sync_sl_test_tm4_p100_c_335 sync_sl_test -p 100 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_s30.72e+6.dat)
# Sample offset
add_test(sync_sl_test_tm4_p25_c_168_so sync_sl_test -p 25 -t 4 -d -o 300 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_s7.68e+6.dat)
# Self-test
add_test(sync_sl_test_self_test_tm4_p25_c_168 sync_sl_test -p 25 -t 4 -c 168 -d)
# Self-test with frequency offset
add_test(sync_sl_test_self_test_tm4_p25_c_168_fo sync_sl_test -p 25 -t 4 -c 168 -d -f 100)
# Self-test with frequency offset and sample offset
add_test(sync_sl_test_self_test_tm4_p25_c_168_fo_so sync_sl_test -p 25 -t 4 -c 168 -d -f 100 -o 3600)
########################################################################
# CFO TEST
########################################################################

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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));
}
}