refactor Sidelink PSBCH and DMRS code

This commit is contained in:
Andre Puschmann 2019-12-20 12:23:28 +01:00
parent e5609e299d
commit 7de51c8236
12 changed files with 1460 additions and 877 deletions

View File

@ -18,34 +18,37 @@
* 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"
#define SRSLTE_SL_MAX_DMRS_SYMB (4)
#define SRSLTE_SL_NOF_PRIME_NUMBERS (196)
typedef struct {
uint32_t nof_prb;
uint32_t sf_n_re;
uint32_t M_sc_rs;
int8_t nr_DMRS_symbols;
int8_t nof_dmrs_symbols;
// Orthogonal Sequence (W) Transmission Mode 1, 2 and PSBCH
int8_t* w;
int8_t w[SRSLTE_SL_MAX_DMRS_SYMB];
// Cyclic Shift Values
int8_t* n_CS;
int8_t n_CS[SRSLTE_SL_MAX_DMRS_SYMB];
// Refrence Signal Cyclic Shift
float* alpha;
// Reference Signal Cyclic Shift
float alpha[SRSLTE_SL_MAX_DMRS_SYMB];
// Group Hopping Flag
uint32_t f_gh;
@ -53,47 +56,53 @@ typedef struct {
uint32_t f_ss;
// Sequence Group Number
uint32_t* u;
uint32_t u[SRSLTE_SL_MAX_DMRS_SYMB];
// Base Sequence Number - always 0 for sidelink
uint32_t v;
int32_t N_zc;
int32_t* q;
int32_t q[SRSLTE_SL_MAX_DMRS_SYMB];
float** r;
float* r[SRSLTE_SL_MAX_DMRS_SYMB];
cf_t** r_uv;
cf_t* r_uv[SRSLTE_SL_MAX_DMRS_SYMB];
cf_t** r_sequence;
cf_t* r_sequence[SRSLTE_SL_MAX_DMRS_SYMB];
cf_t** dmrs_received;
cf_t* pilot_estimates_1;
cf_t* pilot_estimates_2;
cf_t* ce;
cf_t* dmrs_received[SRSLTE_SL_MAX_DMRS_SYMB];
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);
int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t N_sl_id);
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 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,
srslte_cp_t cp);
void srslte_chest_sl_psbch_ls_estimate_equalize(srslte_chest_sl_t* q,
cf_t* sf_buffer,
cf_t* sf_buffer_rx,
uint32_t nof_prb,
srslte_sl_tm_t txMode,
srslte_cp_t cp);
int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q,
cf_t* sf_buffer_rx,
cf_t** dmrs_received,
srslte_sl_tm_t tx_mode,
uint32_t nof_prb,
srslte_cp_t cp);
void srslte_chest_sl_free(srslte_chest_sl_t* q);

View File

@ -331,19 +331,46 @@ typedef struct SRSLTE_API {
///< Sidelink
typedef enum SRSLTE_API {
SRSLTE_SIDELINK_TM1,
SRSLTE_SIDELINK_TM1 = 0,
SRSLTE_SIDELINK_TM2,
SRSLTE_SIDELINK_TM3,
SRSLTE_SIDELINK_TM4
} srslte_sl_tm_t;
typedef enum SRSLTE_API {
SRSLTE_SIDELINK_PSBCH,
SRSLTE_SIDELINK_PSBCH = 0,
SRSLTE_SIDELINK_PSCCH,
SRSLTE_SIDELINK_PSSCH,
SRSLTE_SIDELINK_PSDCH
} srslte_sl_channels_t;
typedef enum SRSLTE_API {
SRSLTE_SIDELINK_DATA_SYMBOL = 0,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_GUARD_SYMBOL
} srslte_sl_symbol_t;
#define SRSLTE_PSBCH_NOF_PRB (6)
#define SRSLTE_PSCCH_TM34_NOF_PRB (2)
#define SRSLTE_MIB_SL_LEN (40) // TM1/2: 40 bits
#define SRSLTE_MIB_SL_V2X_LEN (48) // TM3/4: 48 bits
#define SRSLTE_MIB_SL_MAX_LEN (SRSLTE_MIB_SL_V2X_LEN)
#define SRSLTE_SL_TM12_DEFAULT_NUM_DMRS_SYMBOLS (2)
#define SRSLTE_SL_TM34_DEFAULT_NUM_DMRS_SYMBOLS (4) ///< In TM3/4, all channels have 4 DMRS by default
#define SRSLTE_PSBCH_TM12_NUM_DATA_SYMBOLS (7) ///< SL-BCH is in 7 OFDM symbols
#define SRSLTE_PSBCH_TM12_NUM_DMRS_SYMBOLS (2) ///< PSBCH has 2 DMRS symbols
#define SRSLTE_PSBCH_TM12_NUM_SYNC_SYMBOLS (4) ///< Two symbols PSSS and two SSSS
#define SRSLTE_PSBCH_TM34_NUM_DATA_SYMBOLS (6) ///< SL-BCH is in 7 OFDM symbols
#define SRSLTE_PSBCH_TM34_NUM_DMRS_SYMBOLS (3) ///< PSBCH has 3 DMRS symbols in TM3 and TM4
#define SRSLTE_PSBCH_TM34_NUM_SYNC_SYMBOLS (4) ///< Two symbols PSSS and two SSSS
///< PHY common function declarations
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);
@ -437,4 +464,6 @@ SRSLTE_API float srslte_band_fu_nbiot(uint32_t ul_earfcn, const float m_ul);
SRSLTE_API char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode);
bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i);
#endif // SRSLTE_PHY_COMMON_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/.
*
*/
#ifndef SRSLTE_MIB_SL_H
#define SRSLTE_MIB_SL_H
#include <stdbool.h>
#include <stdint.h>
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
/**
* Master information block - Sidelink (MIB-SL and MIB-SL-V2X).
*
* \brief MIB-SL packing/unpacking functions to convert between bit streams
*
* Reference: 3GPP TS 36.331 version 15.6.0 Release 15 Sec. 6.5
*/
typedef struct SRSLTE_API {
uint32_t mib_sl_len;
// 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
// TM2: (19 bits)
// TM4: (27 bits)
} srslte_mib_sl_t;
SRSLTE_API int srslte_mib_sl_init(srslte_mib_sl_t* q, srslte_sl_tm_t tm);
SRSLTE_API int srslte_mib_sl_set(srslte_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);
SRSLTE_API void srslte_mib_sl_pack(srslte_mib_sl_t* q, uint8_t* msg);
SRSLTE_API void srslte_mib_sl_unpack(srslte_mib_sl_t* q, uint8_t* msg);
SRSLTE_API void srslte_mib_sl_free(srslte_mib_sl_t* q);
SRSLTE_API void srslte_mib_sl_printf(FILE* f, srslte_mib_sl_t* q);
#endif // SRSLTE_MIB_SL_H

View File

@ -31,50 +31,59 @@
#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;
/**
* \brief Physical Sidelink broadcast channel.
*
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6
*/
typedef struct SRSLTE_API {
uint32_t N_sl_id;
srslte_sl_tm_t tm;
srslte_cp_t cp;
uint32_t nof_data_re;
uint32_t E;
uint32_t Qm;
uint32_t len_after_mod;
uint32_t nof_prb;
uint32_t nof_symbols;
uint32_t N_sl_id;
uint32_t nof_data_symbols;
uint32_t sl_bch_tb_len;
uint32_t sl_bch_tb_crc_len;
uint32_t sl_bch_encoded_len;
float precoding_scaling;
uint32_t nof_prb_psbch;
// data
uint8_t* a;
uint8_t* c;
// crc
uint32_t crc_poly;
srslte_crc_t crc_mib;
srslte_crc_t crc_mib_sl;
uint8_t* crc_temp;
// channel coding
srslte_viterbi_t dec;
srslte_convcoder_t encoder;
uint8_t* d;
float* d_float;
// rate matching
uint8_t* e;
int16_t* e_16;
float* e_float;
uint8_t* codeword;
float* llr;
// interleaving
uint8_t* temp_g_bits;
uint32_t* interleaver;
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
cf_t* mod_symbols;
// dft precoding
srslte_dft_precoding_t dft_precoder;
@ -83,14 +92,19 @@ typedef struct {
} srslte_psbch_t;
int srslte_psbch_init(srslte_psbch_t* q, uint32_t N_sl_id, uint32_t nof_prb);
SRSLTE_API int
srslte_psbch_init(srslte_psbch_t* q, uint32_t nof_prb, uint32_t N_sl_id, srslte_sl_tm_t tm, srslte_cp_t cp);
void srslte_psbch_encode(srslte_psbch_t* q, uint8_t* mib_sl);
int srslte_psbch_decode(srslte_psbch_t* q, uint8_t* mib_sl);
SRSLTE_API void srslte_psbch_free(srslte_psbch_t* q);
void srslte_psbch_put(srslte_psbch_t* q, cf_t* sf_buffer);
void srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer);
SRSLTE_API int srslte_psbch_encode(srslte_psbch_t* q, uint8_t* input, uint32_t input_len, cf_t* sf_buffer);
void srslte_psbch_free(srslte_psbch_t* q);
SRSLTE_API int srslte_psbch_decode(srslte_psbch_t* q, cf_t* scfdma_symbols, uint8_t* output, uint32_t max_output_len);
SRSLTE_API int srslte_psbch_reset(srslte_psbch_t* q, uint32_t N_sl_id);
SRSLTE_API int srslte_psbch_put(srslte_psbch_t* q, cf_t* symbols, cf_t* sf_buffer);
SRSLTE_API int srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer, cf_t* symbols);
#endif // SRSLTE_PSBCH_H

View File

@ -18,34 +18,71 @@
* 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/mimo/precoding.h"
#include "srslte/phy/utils/debug.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
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);
for (int i = 0; i < SRSLTE_SL_MAX_DMRS_SYMB; i++) {
q->r[i] = srslte_vec_malloc(sizeof(float) * SRSLTE_MAX_PRB * SRSLTE_NRE);
if (!q->r[i]) {
ERROR("Error allocating memory");
return SRSLTE_ERROR;
}
q->r_uv[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE);
if (!q->r_uv[i]) {
ERROR("Error allocating memory");
return SRSLTE_ERROR;
}
q->r_sequence[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE);
if (!q->r_sequence[i]) {
ERROR("Error allocating memory");
return SRSLTE_ERROR;
}
q->dmrs_received[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE);
if (!q->dmrs_received[i]) {
ERROR("Error allocating memory");
return SRSLTE_ERROR;
}
}
q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS_SYMB); // MAX PERIOD LENGTH 320
if (!q->f_gh_pattern) {
ERROR("Error allocating memory");
return SRSLTE_ERROR;
}
srslte_group_hopping_f_gh(q->f_gh_pattern, N_sa_id);
q->ce = srslte_vec_malloc(sizeof(cf_t) * 2 * SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * SRSLTE_MAX_PRB);
if (!q->ce) {
ERROR("Error allocating memory");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
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;
float q_hat = n_sz * (u + 1) / 31;
if ((((uint32_t)(2 * q_hat)) % 2) == 0) {
q = q_hat + 0.5 + v;
} else {
@ -54,102 +91,263 @@ static uint32_t get_q(uint32_t u, uint32_t v, uint32_t N_sz)
return (uint32_t)q;
}
static void interpolate_pilots_sl_psbch(srslte_interp_linsrslte_vec_t* q, cf_t* ce, uint32_t n_prb)
int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
srslte_sl_tm_t tm,
srslte_sl_channels_t ch,
uint32_t sf_idx,
uint32_t N_sl_id,
uint32_t L_crb,
uint32_t N_sa_id)
{
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");
// M_sc_rs - Reference Signal Length
switch (ch) {
case SRSLTE_SIDELINK_PSBCH:
q->M_sc_rs = SRSLTE_PSBCH_NOF_PRB * SRSLTE_NRE;
break;
case SRSLTE_SIDELINK_PSCCH:
q->M_sc_rs = SRSLTE_NRE;
if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
q->M_sc_rs = SRSLTE_PSCCH_TM34_NOF_PRB * SRSLTE_NRE;
}
break;
case SRSLTE_SIDELINK_PSSCH:
q->M_sc_rs = L_crb * SRSLTE_NRE;
break;
case SRSLTE_SIDELINK_PSDCH:
printf("channel not supported yet\n\n");
break;
default:
printf("channel not supported\n\n");
return SRSLTE_ERROR;
}
// Number of DMRS symbols
if (tm <= SRSLTE_SIDELINK_TM2) {
q->nof_dmrs_symbols = SRSLTE_SL_TM12_DEFAULT_NUM_DMRS_SYMBOLS;
} else {
if (ch == SRSLTE_SIDELINK_PSBCH) {
// only PSBCH has fewer symbols
q->nof_dmrs_symbols = SRSLTE_PSBCH_TM34_NUM_DMRS_SYMBOLS;
} else {
// all other channels have 4 DMRS
q->nof_dmrs_symbols = SRSLTE_SL_TM12_DEFAULT_NUM_DMRS_SYMBOLS;
}
}
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;
// Cyclic Shift
// 36.211, Section 9.8
switch (ch) {
case SRSLTE_SIDELINK_PSBCH:
for (int i = 0; i < q->nof_dmrs_symbols; i++) {
q->n_CS[i] = (int)(N_sl_id / 2) % 8;
}
break;
case SRSLTE_SIDELINK_PSCCH:
if (tm <= SRSLTE_SIDELINK_TM2) {
for (int i = 0; i < q->nof_dmrs_symbols; i++) {
q->n_CS[i] = 0;
}
} else {
for (int i = 0; i < q->nof_dmrs_symbols; i++) {
// TODO: TS 36.213 Section 14.2.1: "The UE shall randomly select the cyclic shift n_CS among {0, 3, 6, 9} in
// each PSCCH transmission."
q->n_CS[i] = 0;
// q->n_CS[i] = i * 3;
}
}
break;
case SRSLTE_SIDELINK_PSSCH:
if (tm <= SRSLTE_SIDELINK_TM2) {
for (int i = 0; i < q->nof_dmrs_symbols; i++) {
q->n_CS[i] = (int)(N_sa_id / 2) % 8;
}
} else {
// TODO: both equation are the same here but spec says N_id_X for Mode3+4
for (int i = 0; i < q->nof_dmrs_symbols; i++) {
q->n_CS[i] = (int)(N_sa_id / 2) % 8;
}
}
break;
case SRSLTE_SIDELINK_PSDCH:
for (int i = 0; i < q->nof_dmrs_symbols; i++) {
q->n_CS[i] = 0;
}
break;
}
// alpha - Reference Signal Cyclic Shift
for (int i = 0; i < q->nof_dmrs_symbols; ++i) {
q->alpha[i] = (2 * M_PI * q->n_CS[i]) / 12;
}
// Group Hopping
// 36.211, Section 10.1.4.1.3
// 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->nof_dmrs_symbols; ++i) {
q->u[i] = (q->f_gh + q->f_ss) % 30;
}
break;
case SRSLTE_SIDELINK_PSCCH:
q->f_gh = 0;
if (tm <= SRSLTE_SIDELINK_TM2) {
q->f_ss = 0;
} else {
q->f_ss = 8;
}
for (int i = 0; i < q->nof_dmrs_symbols; ++i) {
q->u[i] = (q->f_gh + q->f_ss) % 30;
}
break;
case SRSLTE_SIDELINK_PSSCH:
if (tm <= SRSLTE_SIDELINK_TM2) {
q->f_gh = 1;
q->f_ss = N_sa_id % 30;
uint32_t delta_ss = 0;
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];
q->u[i++] = (f_gh + q->f_ss + delta_ss) % 30;
}
} else {
// TM3/4
q->f_gh = 1;
q->f_ss = (N_sa_id / 16) % 30;
uint32_t delta_ss = 0;
for (uint32_t ns = 0; ns <= q->nof_dmrs_symbols; ns++) {
uint32_t f_gh = q->f_gh_pattern[ns];
q->u[ns] = (f_gh + q->f_ss + delta_ss) % 30;
}
}
break;
case SRSLTE_SIDELINK_PSDCH:
q->f_gh = 0;
q->f_ss = 0;
for (int i = 0; i < q->nof_dmrs_symbols; ++i) {
q->u[i] = (q->f_gh + q->f_ss) % 30;
}
break;
}
// N_zc - Zadoff Chu Sequence Length
// TODO: the refsignal_ul.c should be reused for this, code looks almost the same
switch (q->M_sc_rs / SRSLTE_NRE) {
case 1:
for (int j = 0; j < q->nof_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->nof_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 = SRSLTE_SL_NOF_PRIME_NUMBERS - 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->nof_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
// 36.211, Section 5.5.1
for (int j = 0; j < q->nof_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
// 36.211, Section 9.8
switch (ch) {
case SRSLTE_SIDELINK_PSBCH:
case SRSLTE_SIDELINK_PSDCH:
if (tm <= 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 {
// TM3/4
if (N_sl_id % 2) {
q->w[0] = 1;
q->w[1] = -1;
q->w[2] = 1;
} else {
q->w[0] = 1;
q->w[1] = 1;
q->w[2] = 1;
}
}
break;
case SRSLTE_SIDELINK_PSCCH:
if (tm <= SRSLTE_SIDELINK_TM2) {
q->w[0] = 1;
q->w[1] = 1;
} else {
q->w[0] = 1;
q->w[1] = 1;
q->w[2] = 1;
q->w[3] = 1;
}
break;
case SRSLTE_SIDELINK_PSSCH:
if (tm <= 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 {
// TM3/4
if (N_sa_id % 2 == 0) {
q->w[0] = 1;
q->w[1] = 1;
q->w[2] = 1;
q->w[3] = 1;
} else {
q->w[0] = 1;
q->w[1] = -1;
q->w[2] = 1;
q->w[3] = -1;
}
}
break;
default:
return SRSLTE_ERROR;
}
for (int j = 0; j < q->nof_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;
@ -160,352 +358,214 @@ 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)
int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t tm, uint32_t N_sl_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;
return srslte_chest_sl_gen_dmrs(q, tm, 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 tm,
uint32_t nof_prb,
srslte_cp_t cp)
{
uint32_t sample_pos = 0;
uint32_t k = nof_prb * SRSLTE_NRE / 2 - 36;
uint32_t sf_nsymbols = 0;
if (tm <= SRSLTE_SIDELINK_TM2) {
sf_nsymbols = (cp == SRSLTE_CP_NORM) ? SRSLTE_CP_NORM_SF_NSYMB : SRSLTE_CP_EXT_SF_NSYMB;
} else {
// TM3/4
sf_nsymbols = SRSLTE_CP_NORM_SF_NSYMB;
}
// 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));
// Mapping to physical resources
for (uint32_t i = 0; i < sf_nsymbols; i++) {
if (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i)) {
memcpy(&sf_buffer[k + i * nof_prb * SRSLTE_NRE], &q->r_sequence[sample_pos][0], q->M_sc_rs * sizeof(cf_t));
sample_pos++;
}
}
// 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)
static void interpolate_pilots_sl_psbch(srslte_interp_linsrslte_vec_t* q,
cf_t* ce,
uint32_t n_prb,
srslte_sl_tm_t tm,
srslte_cp_t cp)
{
return srslte_chest_sl_gen_dmrs(q, txMode, nof_prb, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0);
}
uint32_t L1;
uint32_t L2;
uint32_t L3;
uint32_t ce_l1;
uint32_t ce_l2;
uint32_t ce_l3;
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;
if (tm <= SRSLTE_SIDELINK_TM2) {
if (cp == SRSLTE_CP_NORM) {
L1 = 3;
L2 = 10;
} else {
L1 = 2;
L2 = 8;
}
} else {
// TM3/4
if (cp == SRSLTE_CP_NORM) {
L1 = 4;
L2 = 6;
L3 = 9;
} else {
ERROR("Invalid CP");
return;
}
}
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;
}
uint32_t NL = 2 * SRSLTE_CP_NSYMB(cp);
uint32_t nre = n_prb * SRSLTE_NRE;
srslte_interp_linear_vector_resize(q, nre);
ce_l1 = SRSLTE_RE_IDX(n_prb, L1, 0 * SRSLTE_NRE);
ce_l2 = SRSLTE_RE_IDX(n_prb, L2, 0 * SRSLTE_NRE);
if (tm <= SRSLTE_SIDELINK_TM2) {
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);
} else {
// TM3/4
ce_l3 = SRSLTE_RE_IDX(n_prb, L3, 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_l2], &ce[ce_l3], NULL, &ce[ce_l2 + nre], (L3 - L2), (L3 - L2) - 1, true, nre);
srslte_interp_linear_vector3(
q, &ce[ce_l2], &ce[ce_l3], &ce[ce_l3], &ce[ce_l3 + nre], (L3 - L2), (NL - L3) - 1, true, nre);
}
}
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* sf_buffer_rx,
uint32_t nof_prb,
srslte_sl_tm_t tm,
srslte_cp_t cp)
{
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");
}
}
int sf_n_re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE * nof_prb * 2;
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);
uint32_t k = nof_prb * SRSLTE_NRE / 2 - 36;
// 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);
bzero(q->ce, sizeof(cf_t) * sf_n_re);
interpolate_pilots_sl_psbch(&q->lin_vec_sl, q->ce, nof_prb);
if (tm <= SRSLTE_SIDELINK_TM2) {
if (cp == SRSLTE_CP_NORM) {
srslte_vec_prod_conj_ccc(&sf_buffer[3 * nof_prb * SRSLTE_NRE + k],
&q->r_sequence[0][0],
&q->ce[3 * nof_prb * SRSLTE_NRE + k],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[10 * nof_prb * SRSLTE_NRE + k],
&q->r_sequence[1][0],
&q->ce[10 * nof_prb * SRSLTE_NRE + k],
q->M_sc_rs);
} else {
srslte_vec_prod_conj_ccc(&sf_buffer[2 * nof_prb * SRSLTE_NRE + k],
&q->r_sequence[0][0],
&q->ce[2 * nof_prb * SRSLTE_NRE + k],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[8 * nof_prb * SRSLTE_NRE + k],
&q->r_sequence[1][0],
&q->ce[8 * nof_prb * SRSLTE_NRE + k],
q->M_sc_rs);
}
} else {
// TM3/4
if (cp == SRSLTE_CP_NORM) {
srslte_vec_prod_conj_ccc(&sf_buffer[4 * nof_prb * SRSLTE_NRE + k],
&q->r_sequence[0][0],
&q->ce[4 * nof_prb * SRSLTE_NRE + k],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[6 * nof_prb * SRSLTE_NRE + k],
&q->r_sequence[1][0],
&q->ce[6 * nof_prb * SRSLTE_NRE + k],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[9 * nof_prb * SRSLTE_NRE + k],
&q->r_sequence[2][0],
&q->ce[9 * nof_prb * SRSLTE_NRE + k],
q->M_sc_rs);
} else {
ERROR("Invalid CP");
return;
}
}
interpolate_pilots_sl_psbch(&q->lin_vec_sl, q->ce, nof_prb, tm, cp);
// Perform channel equalization
srslte_predecoding_single(sf_buffer, q->ce, output, NULL, sf_n_re, 1, 0.0);
srslte_predecoding_single(sf_buffer, q->ce, sf_buffer_rx, NULL, sf_n_re, 1, 0.0);
}
int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q,
cf_t* sf_buffer_rx,
cf_t** dmrs_received,
srslte_sl_tm_t tm,
uint32_t nof_prb,
srslte_cp_t cp)
{
uint32_t sample_pos = 0;
uint32_t k = nof_prb * SRSLTE_NRE / 2 - 36;
uint32_t sf_nsymbols = SRSLTE_CP_NORM_SF_NSYMB;
// Get DMRSs
for (uint32_t i = 0; i < sf_nsymbols; i++) {
if (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i)) {
memcpy(&q->dmrs_received[sample_pos][0], &sf_buffer_rx[k + i * nof_prb * SRSLTE_NRE], q->M_sc_rs * sizeof(cf_t));
sample_pos++;
}
}
for (uint32_t i = 0; i < q->nof_dmrs_symbols; i++) {
memcpy(&dmrs_received[i][0], &q->dmrs_received[i][0], q->M_sc_rs * sizeof(cf_t));
}
return sample_pos;
}
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) {
for (int i = 0; i < SRSLTE_SL_MAX_DMRS_SYMB; i++) {
if (q->r[i]) {
free(q->r[i]);
}
free(q->r);
}
if (q->r_uv) {
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) {
if (q->r_uv[i]) {
free(q->r_uv[i]);
}
free(q->r_uv);
}
if (q->r_sequence) {
for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) {
if (q->r_sequence[i]) {
free(q->r_sequence[i]);
}
free(q->r_sequence);
}
if (q->u) {
free(q->u);
if (q->dmrs_received[i]) {
free(q->dmrs_received[i]);
}
}
if (q->f_gh_pattern) {
free(q->f_gh_pattern);
}
if (q->ce) {
free(q->ce);
}
}
}

View File

@ -811,4 +811,46 @@ char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode)
default:
return "N/A";
}
}
}
///< Sidelink helpers
///< Look-up tables for Sidelink channel symbols
srslte_sl_symbol_t srslte_psbch_symbol_map_tm12[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_GUARD_SYMBOL};
srslte_sl_symbol_t srslte_psbch_symbol_map_tm34[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_GUARD_SYMBOL};
bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i)
{
if (tm <= SRSLTE_SIDELINK_TM2) {
return srslte_psbch_symbol_map_tm12[i] == type;
} else {
return srslte_psbch_symbol_map_tm34[i] == type;
}
}

123
lib/src/phy/phch/mib_sl.c Normal file
View File

@ -0,0 +1,123 @@
/*
* 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 <strings.h>
#include "srslte/phy/phch/mib_sl.h"
#include "srslte/phy/utils/bit.h"
//#include "srslte/phy/common/phy_sl_common.h"
int srslte_mib_sl_init(srslte_mib_sl_t* q, srslte_sl_tm_t tm)
{
if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) {
q->mib_sl_len = SRSLTE_MIB_SL_LEN;
} else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
q->mib_sl_len = SRSLTE_MIB_SL_V2X_LEN;
} else {
return SRSLTE_ERROR;
}
q->sl_bandwidth_r12 = 0;
q->direct_frame_number_r12 = 0;
q->direct_subframe_number_r12 = 0;
q->in_coverage_r12 = false;
q->tdd_config_sl_r12 = 0;
return SRSLTE_SUCCESS;
}
int srslte_mib_sl_set(srslte_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_mib_sl_pack(srslte_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 srslte_mib_sl_unpack(srslte_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_mib_sl_printf(FILE* f, srslte_mib_sl_t* q)
{
fprintf(f, " - Bandwidth: %i\n", q->sl_bandwidth_r12);
fprintf(f, " - Direct Frame Number: %i\n", q->direct_frame_number_r12);
fprintf(f, " - Direct Subframe Number: %i\n", q->direct_subframe_number_r12);
fprintf(f, " - TDD config: %i\n", q->tdd_config_sl_r12);
fprintf(f, " - In coverage: %s\n", q->in_coverage_r12 ? "yes" : "no");
}
void srslte_mib_sl_free(srslte_mib_sl_t* q)
{
if (q != NULL) {
bzero(q, sizeof(srslte_mib_sl_t));
}
}

View File

@ -19,16 +19,18 @@
*
*/
#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 "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>
#define HAVE_INTERLEAVING 1
#if HAVE_INTERLEAVING
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;
@ -50,293 +52,348 @@ void slbch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32
}
}
}
#endif // HAVE_INTERLEAVING
int srslte_psbch_init(srslte_psbch_t* q, uint32_t N_sl_id, uint32_t nof_prb)
int srslte_psbch_init(srslte_psbch_t* q, uint32_t nof_prb, uint32_t N_sl_id, srslte_sl_tm_t tm, srslte_cp_t cp)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
bzero(q, sizeof(srslte_psbch_t));
if (q != NULL) {
q->N_sl_id = N_sl_id;
q->tm = tm;
ret = SRSLTE_ERROR;
q->nof_prb = nof_prb;
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;
if (SRSLTE_CP_ISEXT(cp)) {
ERROR("Extended CP is not supported yet.");
return SRSLTE_ERROR;
}
q->cp = cp;
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]];
// Calculate rate matching params
if (q->tm <= SRSLTE_SIDELINK_TM2) {
q->nof_data_symbols = SRSLTE_PSBCH_TM12_NUM_DATA_SYMBOLS;
q->sl_bch_tb_len = SRSLTE_MIB_SL_LEN;
} else {
q->nof_data_symbols = SRSLTE_PSBCH_TM34_NUM_DATA_SYMBOLS;
q->sl_bch_tb_len = SRSLTE_MIB_SL_V2X_LEN;
}
q->nof_data_re = q->nof_data_symbols * (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB);
q->sl_bch_tb_crc_len = q->sl_bch_tb_len + SRSLTE_SL_BCH_CRC_LEN;
q->sl_bch_encoded_len = 3 * q->sl_bch_tb_crc_len;
// ********************************************************************************************************
// 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");
q->c = srslte_vec_malloc(sizeof(uint8_t) * q->sl_bch_tb_crc_len);
if (!q->c) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->d = srslte_vec_malloc(sizeof(uint8_t) * q->sl_bch_encoded_len);
if (!q->d) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->d_float = srslte_vec_malloc(sizeof(float) * q->sl_bch_encoded_len);
if (!q->d_float) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
// CRC
if (srslte_crc_init(&q->crc_mib_sl, SRSLTE_LTE_CRC16, 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 memory\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));
if (srslte_viterbi_init(&q->dec, SRSLTE_VITERBI_37, poly, q->sl_bch_tb_crc_len, true)) {
return SRSLTE_ERROR;
}
// QPSK modulation
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6 - Table 9.6.2-1: PSBCH modulation schemes
q->Qm = srslte_mod_bits_x_symbol(SRSLTE_MOD_QPSK);
q->E = q->nof_data_re * q->Qm;
q->e = srslte_vec_malloc(sizeof(uint8_t) * q->E);
if (!q->e) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->e_float = srslte_vec_malloc(sizeof(float) * q->E);
if (!q->e_float) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
#if HAVE_INTERLEAVING
// Interleaving
q->interleaver_lut = srslte_vec_malloc(sizeof(uint32_t) * q->E);
if (!q->interleaver_lut) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
slbch_interleave_gen(q->nof_data_re, q->nof_data_symbols, q->Qm, q->interleaver_lut);
#endif
// Scrambling
bzero(&q->seq, sizeof(srslte_sequence_t));
if (srslte_sequence_LTE_pr(&q->seq, q->E, N_sl_id) != SRSLTE_SUCCESS) {
ERROR("Error srslte_sequence_LTE_pr\n");
return SRSLTE_ERROR;
}
q->codeword = srslte_vec_malloc(sizeof(uint8_t) * q->E);
if (!q->codeword) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
// Modulation QPSK
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK) != SRSLTE_SUCCESS) {
ERROR("Error srslte_modem_table_lte\n");
return SRSLTE_ERROR;
}
q->mod_symbols = srslte_vec_malloc(sizeof(cf_t) * q->nof_data_re);
if (!q->mod_symbols) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->llr = srslte_vec_malloc(sizeof(float) * q->E);
if (!q->llr) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
// Transform precoding
q->precoding_scaling = 1.0;
if (srslte_dft_precoding_init_tx(&q->dft_precoder, SRSLTE_PSBCH_NOF_PRB) != SRSLTE_SUCCESS) {
ERROR("Error srslte_dft_precoding_init\n");
return SRSLTE_ERROR;
}
q->scfdma_symbols = srslte_vec_malloc(sizeof(cf_t) * q->nof_data_re);
if (!q->scfdma_symbols) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
if (srslte_dft_precoding_init_rx(&q->idft_precoder, SRSLTE_PSBCH_NOF_PRB) != SRSLTE_SUCCESS) {
ERROR("Error srslte_idft_precoding_init\n");
return SRSLTE_ERROR;
}
memcpy(mib_sl, q->a, sizeof(uint8_t) * SRSLTE_SL_BCH_PAYLOAD_LEN);
return SRSLTE_SUCCESS;
}
int srslte_psbch_encode(srslte_psbch_t* q, uint8_t* input, uint32_t input_len, cf_t* sf_buffer)
{
if (input == NULL || input_len > q->sl_bch_tb_len) {
ERROR("Can't encode PSBCH, input too long (%d > %d)\n", input_len, q->sl_bch_tb_len);
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Copy into codeword buffer
memcpy(q->c, input, sizeof(uint8_t) * input_len);
// CRC Attachment
srslte_crc_attach(&q->crc_mib_sl, q->c, input_len);
// Channel Coding
srslte_convcoder_encode(&q->encoder, q->c, q->d, q->sl_bch_tb_crc_len);
// Rate matching
srslte_rm_conv_tx(q->d, q->sl_bch_encoded_len, q->codeword, q->E);
#if HAVE_INTERLEAVING
// PUSCH de-interleaving
for (int i = 0; i < q->E; i++) {
q->e[i] = q->codeword[q->interleaver_lut[i]];
}
#endif
// Scrambling
srslte_scrambling_b(&q->seq, q->e);
// Modulation
srslte_mod_modulate(&q->mod, q->e, q->mod_symbols, q->E);
// Layer Mapping
// Void: Single layer
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.3
// Transform precoding
srslte_dft_precoding(&q->dft_precoder, q->mod_symbols, q->scfdma_symbols, SRSLTE_PSBCH_NOF_PRB, q->nof_data_symbols);
// Precoding
// Void: Single antenna port
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.5
// RE mapping
srslte_psbch_put(q, q->scfdma_symbols, sf_buffer);
return SRSLTE_SUCCESS;
}
int srslte_psbch_decode(srslte_psbch_t* q, cf_t* equalized_sf_syms, uint8_t* output, uint32_t max_output_len)
{
if (max_output_len < q->sl_bch_tb_len) {
ERROR("Can't decode PSBCH, provided buffer too small (%d < %d)\n", max_output_len, q->sl_bch_tb_len);
return SRSLTE_ERROR;
}
// RE extraction
if (q->nof_data_re != srslte_psbch_get(q, equalized_sf_syms, q->scfdma_symbols)) {
ERROR("There was an error getting the PSBCH symbols\n");
return SRSLTE_ERROR;
}
// Precoding
// Void: Single antenna port
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.5
// Transform precoding
srslte_dft_precoding(&q->idft_precoder, q->scfdma_symbols, q->mod_symbols, SRSLTE_PSBCH_NOF_PRB, q->nof_data_symbols);
// Layer Mapping
// Void: Single layer
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.3
// Demodulation
srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->mod_symbols, q->e_float, q->nof_data_re);
// De-scramble
srslte_scrambling_f(&q->seq, q->e_float);
#if HAVE_INTERLEAVING
// Deinterleaving
for (int i = 0; i < q->E; i++) {
q->e_float[q->interleaver_lut[i]] = q->e_float[i];
}
#endif
// Rate match
srslte_rm_conv_rx(q->e_float, q->E, q->d_float, q->sl_bch_encoded_len);
// Channel decoding
srslte_viterbi_decode_f(&q->dec, q->d_float, q->c, q->sl_bch_tb_crc_len);
printf("after viterbi\n");
srslte_vec_fprint_b(stdout, q->c, q->sl_bch_tb_crc_len);
// Copy received crc to temp
memcpy(q->crc_temp, &q->c[q->sl_bch_tb_len], sizeof(uint8_t) * SRSLTE_SL_BCH_CRC_LEN);
// Re-attach crc
srslte_crc_attach(&q->crc_mib_sl, q->c, q->sl_bch_tb_len);
// CRC check
if (srslte_bit_diff(q->crc_temp, &q->c[q->sl_bch_tb_len], SRSLTE_SL_BCH_CRC_LEN) != 0) {
return SRSLTE_ERROR;
}
// Remove CRC and copy to output buffer
memcpy(output, q->c, sizeof(uint8_t) * q->sl_bch_tb_len);
return SRSLTE_SUCCESS;
}
int srslte_psbch_reset(srslte_psbch_t* q, uint32_t N_sl_id)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
if (q->N_sl_id != N_sl_id) {
q->N_sl_id = N_sl_id;
// Regen scrambling sequence
if (srslte_sequence_LTE_pr(&q->seq, q->E, N_sl_id) != SRSLTE_SUCCESS) {
ERROR("Error srslte_sequence_LTE_pr\n");
return SRSLTE_ERROR;
}
}
ret = SRSLTE_SUCCESS;
}
return ret;
}
int srslte_psbch_put(srslte_psbch_t* q, cf_t* symbols, cf_t* sf_buffer)
{
uint32_t sample_pos = 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 (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i)) {
memcpy(&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE],
&symbols[sample_pos],
sizeof(cf_t) * (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB));
sample_pos += (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB);
}
}
return sample_pos;
}
int srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer, cf_t* symbols)
{
uint32_t sample_pos = 0;
uint32_t k = q->nof_prb * SRSLTE_NRE / 2 - 36;
// Get PSBCH REs
for (uint32_t i = 0; i < SRSLTE_CP_NORM_SF_NSYMB; i++) {
if (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i)) {
memcpy(&symbols[sample_pos],
&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE],
sizeof(cf_t) * (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB));
sample_pos += (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB);
}
}
return sample_pos;
}
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->crc_temp) {
free(q->crc_temp);
}
if (q->c) {
free(q->c);
}
if (q->d) {
free(q->d);
}
if (q->crc_temp) {
free(q->crc_temp);
if (q->d_float) {
free(q->d_float);
}
if (q->e) {
free(q->e);
}
if (q->e_16) {
free(q->e_16);
if (q->e_float) {
free(q->e_float);
}
if (q->interleaver_lut) {
free(q->interleaver_lut);
@ -344,16 +401,16 @@ void srslte_psbch_free(srslte_psbch_t* q)
if (q->codeword) {
free(q->codeword);
}
if (q->symbols) {
free(q->symbols);
}
if (q->llr) {
free(q->llr);
}
if (q->mod_symbols) {
free(q->mod_symbols);
}
if (q->scfdma_symbols) {
free(q->scfdma_symbols);
}
bzero(q, sizeof(srslte_psbch_t));
}
}
}

View File

@ -40,16 +40,24 @@ 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)
add_test(psbch_test_self_test_tm2_p6_c168_self psbch_test -p 6 -c 168 -t 2)
add_test(psbch_test_self_test_tm2_p50_c168_self psbch_test -p 50 -c 252 -t 2)
add_test(psbch_test_self_test_tm2_p100_c168_self psbch_test -p 100 -c 335 -t 2)
# TM4 self tests
add_test(psbch_test_self_test_tm4_p6_c168_self psbch_test -p 6 -c 168 -t 4)
add_test(psbch_test_self_test_tm4_p50_c168_self psbch_test -p 50 -c 252 -t 4)
add_test(psbch_test_self_test_tm4_p100_c168_self psbch_test -p 100 -c 335 -t 4)
add_executable(psbch_file_test psbch_file_test.c)
target_link_libraries(psbch_file_test srslte_phy)
# 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)
#add_test(psbch_file_test_ideal_tm2_p6_c0 psbch_test -p 6 -t 2 -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 -t 2 -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 -t 2 -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 -t 2 -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 -t 2 -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,219 @@
/*
* 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 <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <srslte/phy/ch_estimation/chest_sl.h>
#include <srslte/phy/dft/ofdm.h>
#include <srslte/phy/io/filesource.h>
#include <srslte/phy/phch/mib_sl.h>
#include <srslte/phy/phch/psbch.h>
#include <srslte/phy/sync/cfo.h>
#include <srslte/phy/utils/debug.h>
#include <srslte/phy/utils/vector.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;
bool do_equalization = true;
srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2;
srslte_filesource_t fsrc;
void usage(char* prog)
{
printf("Usage: %s [cdeipt]\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-d use_standard_lte_rates [Default %i]\n", use_standard_lte_rates);
printf("\t-s skip equalization [Default no]\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-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "cdeisptv")) != -1) {
switch (opt) {
case 'c':
N_sl_id = atoi(argv[optind]);
break;
case 'd':
use_standard_lte_rates = true;
break;
case 's':
do_equalization = false;
break;
case 'e':
cp = SRSLTE_CP_EXT;
break;
case 'i':
input_file_name = argv[optind];
break;
case 'p':
nof_prb = atoi(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)
{
int ret = SRSLTE_ERROR;
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(cp) * SRSLTE_NRE * 2 * nof_prb;
cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
cf_t* equalized_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* output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
// TX
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);
// RX
srslte_ofdm_t fft;
if (srslte_ofdm_rx_init(&fft, cp, input_buffer, sf_buffer, nof_prb)) {
fprintf(stderr, "Error creating FFT object\n");
return SRSLTE_ERROR;
}
srslte_ofdm_set_normalize(&fft, true);
srslte_ofdm_set_freq_shift(&fft, -0.5);
// PSBCH
srslte_psbch_t psbch;
srslte_psbch_init(&psbch, nof_prb, N_sl_id, tm, SRSLTE_CP_NORM);
// PSCBH DMRS
srslte_chest_sl_t psbch_chest;
srslte_chest_sl_init_psbch_dmrs(&psbch_chest);
// Read subframe from third party implementations
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;
}
srslte_filesource_read(&fsrc, input_buffer, sf_n_samples);
// srslte_vec_sc_prod_cfc(input_buffer, sqrtf(symbol_sz), input_buffer, sf_n_samples);
// Run FFT
srslte_ofdm_rx_sf(&fft);
// Equalize
if (do_equalization) {
srslte_chest_sl_gen_psbch_dmrs(&psbch_chest, tm, N_sl_id);
srslte_chest_sl_psbch_ls_estimate_equalize(&psbch_chest, sf_buffer, equalized_sf_buffer, nof_prb, tm, cp);
} else {
// just copy symbols
memcpy(equalized_sf_buffer, sf_buffer, sizeof(cf_t) * sf_n_re);
}
// prepare Rx buffer
uint8_t mib_sl_rx[SRSLTE_MIB_SL_MAX_LEN] = {};
// Decode PSBCH
if (srslte_psbch_decode(&psbch, equalized_sf_buffer, mib_sl_rx, sizeof(mib_sl_rx)) == SRSLTE_SUCCESS) {
printf("Rx payload: ");
srslte_vec_fprint_hex(stdout, mib_sl_rx, sizeof(mib_sl_rx));
// Unpack and print MIB-SL
srslte_mib_sl_t mib_sl;
srslte_mib_sl_init(&mib_sl, tm);
srslte_mib_sl_unpack(&mib_sl, mib_sl_rx);
srslte_mib_sl_printf(stdout, &mib_sl);
ret = SRSLTE_SUCCESS;
}
if (SRSLTE_VERBOSE_ISDEBUG()) {
char* filename = (do_equalization) ? "psbch_rx_syms_eq_on.bin" : "psbch_rx_syms_eq_off.bin";
printf("Saving PSBCH symbols (%d) to %s\n", psbch.E / psbch.Qm, filename);
srslte_vec_save_file(filename, psbch.mod_symbols, psbch.E / psbch.Qm * sizeof(cf_t));
}
srslte_ofdm_tx_free(&ifft);
srslte_ofdm_rx_free(&fft);
srslte_filesource_free(&fsrc);
srslte_chest_sl_free(&psbch_chest);
srslte_psbch_free(&psbch);
free(sf_buffer);
free(equalized_sf_buffer);
free(input_buffer);
free(output_buffer);
return ret;
}

View File

@ -18,53 +18,70 @@
* and at http://www.gnu.org/licenses/.
*
*/
#include <srslte/phy/utils/vector.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "srslte/phy/dft/ofdm.h"
#include "srslte/common/test_common.h"
#include <srslte/phy/phch/mib_sl.h>
#include <srslte/phy/phch/psbch.h>
#include <srslte/phy/utils/debug.h>
#include <srslte/phy/utils/vector.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;
int32_t N_sl_id = 168;
srslte_cp_t cp = SRSLTE_CP_NORM;
uint32_t nof_prb = 6;
srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2;
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("Usage: %s [cdeipt]\n", prog);
printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-e extended CP [Default normal]\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-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "cdip")) != -1) {
while ((opt = getopt(argc, argv, "ceiptv")) != -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];
case 'e':
cp = SRSLTE_CP_EXT;
break;
case 'p':
nof_prb = atoi(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);
@ -74,137 +91,64 @@ void parse_args(int argc, char** argv)
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);
parse_args(argc, argv);
cf_t* sf_buffer_samples = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
bzero(sf_buffer_samples, sizeof(cf_t) * sf_n_samples);
uint32_t sf_n_re = SRSLTE_SF_LEN_RE(nof_prb, cp);
cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
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);
// MIB-SL
srslte_mib_sl_t mib_sl;
srslte_mib_sl_init(&mib_sl, tm);
srslte_mib_sl_set(&mib_sl, nof_prb, 0, 128, 4, false);
// PSBCH
srslte_psbch_t psbch;
if (srslte_psbch_init(&psbch, N_sl_id, nof_prb)) {
printf("Error creating PSBCH object\n");
return SRSLTE_ERROR;
}
srslte_psbch_init(&psbch, nof_prb, N_sl_id, tm, SRSLTE_CP_NORM);
srslte_ue_mib_sl_t mib_sl;
srslte_ue_mib_sl_set(&mib_sl, nof_prb, 0, 0, 0, false);
// MIB message bits
uint8_t mib_sl_tx[SRSLTE_MIB_SL_MAX_LEN] = {};
srslte_mib_sl_pack(&mib_sl, mib_sl_tx);
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);
printf("Tx payload: ");
srslte_vec_fprint_hex(stdout, mib_sl_tx, mib_sl.mib_sl_len);
if (!input_file_name) {
// *************************************************************************************************************
// PSBCH ENCODING
// *************************************************************************************************************
srslte_ue_mib_sl_pack(&mib_sl, psbch.a);
srslte_psbch_encode(&psbch, psbch.a);
// Put MIB-SL into PSBCH
srslte_psbch_encode(&psbch, mib_sl_tx, mib_sl.mib_sl_len, sf_buffer);
// Map PSBCH to subframe
srslte_psbch_put(&psbch, sf_buffer);
// prepare Rx buffer
uint8_t mib_sl_rx[SRSLTE_MIB_SL_MAX_LEN] = {};
// Map PSBCH DMRS to subframe
srslte_chest_sl_put_psbch_dmrs(&psbch_est, sf_buffer, SRSLTE_SIDELINK_TM2, nof_prb);
// Decode PSBCH
if (srslte_psbch_decode(&psbch, sf_buffer, mib_sl_rx, sizeof(mib_sl_rx)) == SRSLTE_SUCCESS) {
printf("Rx payload: ");
srslte_vec_fprint_hex(stdout, mib_sl_rx, mib_sl.mib_sl_len);
// 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);
srslte_mib_sl_unpack(&mib_sl, mib_sl_rx);
srslte_mib_sl_printf(stdout, &mib_sl);
} 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);
// Sanity check
if (tm <= SRSLTE_SIDELINK_TM2) {
// TM1 and TM2 have always 504 PSBCH resource elements
TESTASSERT(psbch.E / psbch.Qm == 504);
} else {
// TM3 and TM4 have always 432 PSBCH resource elements
TESTASSERT(psbch.E / psbch.Qm == 432);
}
if (SRSLTE_VERBOSE_ISDEBUG()) {
printf("PSBCH eq. symbols (%d), saving to psbch_rx_syms.bin\n", psbch.E / psbch.Qm);
srslte_vec_fprint_c(stdout, psbch.mod_symbols, 8);
srslte_vec_save_file("psbch_rx_syms.bin", psbch.mod_symbols, psbch.E / psbch.Qm * sizeof(cf_t));
}
srslte_mib_sl_free(&mib_sl);
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

@ -34,8 +34,6 @@
#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;