diff --git a/lib/include/srslte/phy/ch_estimation/chest_sl.h b/lib/include/srslte/phy/ch_estimation/chest_sl.h index bd297be92..f0383eb46 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_sl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_sl.h @@ -30,8 +30,12 @@ #include "srslte/phy/common/phy_common.h" #include "srslte/phy/resampling/interp.h" +#define SRSLTE_SL_N_RU_SEQ (30) #define SRSLTE_SL_MAX_DMRS_SYMB (4) -#define SRSLTE_SL_NOF_PRIME_NUMBERS (196) + +// Base Sequence Number - always 0 for sidelink: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 5.5.1.4 +#define SRSLTE_SL_BASE_SEQUENCE_NUMBER 0 +#define SRSLTE_SL_MAX_DMRS_PERIOD_LENGTH 320 typedef struct { @@ -80,6 +84,15 @@ typedef struct { } srslte_chest_sl_t; +SRSLTE_API 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_x_id, + uint32_t cyclic_shift); + SRSLTE_API int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q); SRSLTE_API int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t N_sl_id); @@ -104,6 +117,33 @@ SRSLTE_API int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q, uint32_t nof_prb, srslte_cp_t cp); +SRSLTE_API int srslte_chest_sl_init_pscch_dmrs(srslte_chest_sl_t* q); + +SRSLTE_API int srslte_chest_sl_gen_pscch_dmrs(srslte_chest_sl_t* q, uint32_t cyclic_shift, srslte_sl_tm_t tm); + +SRSLTE_API int srslte_chest_sl_put_pscch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer, + uint32_t prb_idx, + srslte_sl_tm_t tm, + uint32_t nof_prb, + srslte_cp_t cp); + +SRSLTE_API void srslte_chest_sl_pscch_ls_estimate_equalize(srslte_chest_sl_t* q, + cf_t* sf_buffer, + uint32_t prb_idx, + cf_t* sf_buffer_rx, + uint32_t nof_prb, + srslte_sl_tm_t tm, + srslte_cp_t cp); + +SRSLTE_API int srslte_chest_sl_get_pscch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer_rx, + uint32_t prb_idx, + cf_t** dmrs_received, + srslte_sl_tm_t tm, + uint32_t nof_prb, + srslte_cp_t cp); + SRSLTE_API void srslte_chest_sl_free(srslte_chest_sl_t* q); #endif \ No newline at end of file diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 18aec4952..8e3a307b6 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -362,6 +362,11 @@ typedef enum SRSLTE_API { SRSLTE_SIDELINK_GUARD_SYMBOL } srslte_sl_symbol_t; +typedef enum { + SRSLTE_SCI_FORMAT0 = 0, + SRSLTE_SCI_FORMAT1 +} srslte_sci_format_t; + #define SRSLTE_PSBCH_NOF_PRB (6) #define SRSLTE_PSCCH_TM34_NOF_PRB (2) @@ -380,6 +385,22 @@ typedef enum SRSLTE_API { #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 +#define SRSLTE_SCI_CRC_LEN (16) +#define SRSLTE_SCI_MAX_LEN (45) +#define SRSLTE_SCI_TM34_LEN (32) + +#define SRSLTE_PSCCH_QM 2 +#define SRSLTE_PSCCH_TM12_NOF_PRB (1) +#define SRSLTE_PSCCH_TM34_NOF_PRB (2) +#define SRSLTE_PSCCH_SCRAMBLING_SEED (510) ///< Scrambling seed for PSCCH is 510 + +#define SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS (12) +#define SRSLTE_PSCCH_TM12_NUM_DMRS_SYMBOLS (2) +#define SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS_EXT (10) + +#define SRSLTE_PSCCH_TM34_NUM_DATA_SYMBOLS (10) +#define SRSLTE_PSCCH_TM34_NUM_DMRS_SYMBOLS (4) + ///< PHY common function declarations SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t* cell); @@ -475,7 +496,10 @@ 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); +SRSLTE_API int srslte_sl_get_num_symbols(srslte_sl_tm_t tm, srslte_cp_t cp); +SRSLTE_API bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i); +SRSLTE_API bool srslte_pscch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i, srslte_cp_t cp); +SRSLTE_API uint32_t srslte_sci_format0_sizeof(uint32_t nof_prb); /** * Returns a constant string pointer with the ACK/NACK feedback mode diff --git a/lib/include/srslte/phy/phch/pscch.h b/lib/include/srslte/phy/phch/pscch.h new file mode 100644 index 000000000..d93d1608e --- /dev/null +++ b/lib/include/srslte/phy/phch/pscch.h @@ -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_PSCCH_H +#define SRSLTE_PSCCH_H + +#include + +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/sequence.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/modem_table.h" + +/** + * \brief Physical Sidelink control channel. + * + * Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Section 9.4 + */ + +typedef struct SRSLTE_API { + + srslte_sl_tm_t tm; + srslte_cp_t cp; + + uint32_t sci_len; + uint32_t nof_tx_re; + + uint32_t pscch_nof_prb; + + // crc + uint8_t* c; + srslte_crc_t crc; + uint8_t* sci_crc; + + // channel coding + srslte_viterbi_t dec; + srslte_convcoder_t encoder; + uint8_t* d; + int16_t* d_16; + + // rate matching + uint32_t E; + uint8_t* e; + int16_t* e_16; + + uint8_t* e_bytes; ///< To pack bits to bytes + uint32_t nof_symbols; + + // interleaving + uint32_t* interleaver_lut; + uint8_t* codeword; + uint8_t* codeword_bytes; + + uint32_t nof_prb; + + // scrambling + srslte_sequence_t seq; + + // modulation + srslte_modem_table_t mod; + cf_t* mod_symbols; + int16_t* llr; + + // dft precoding + srslte_dft_precoding_t dft_precoder; + srslte_dft_precoding_t idft_precoder; + + cf_t* scfdma_symbols; + +} srslte_pscch_t; + +SRSLTE_API int srslte_pscch_init(srslte_pscch_t* q, uint32_t nof_prb, srslte_sl_tm_t tm, srslte_cp_t cp); +SRSLTE_API int srslte_pscch_encode(srslte_pscch_t* q, uint8_t* sci, cf_t* sf_buffer, uint32_t prb_idx); +SRSLTE_API int srslte_pscch_decode(srslte_pscch_t* q, cf_t* equalized_sf_syms, uint8_t* sci, uint32_t prb_idx); +SRSLTE_API int srslte_pscch_put(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx); +SRSLTE_API int srslte_pscch_get(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx); +SRSLTE_API void srslte_pscch_free(srslte_pscch_t* q); + +#endif // SRSLTE_PSCCH_H diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index 6f1b46d3c..044eefb59 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -131,10 +131,10 @@ SRSLTE_API void srslte_sl_ulsch_interleave(uint8_t* g_bits, ///< Sidelink uses PUSCH Deinterleaver in all channels SRSLTE_API void srslte_sl_ulsch_deinterleave(int16_t* q_bits, - uint32_t Qm, - uint32_t H_prime_total, - uint32_t N_pusch_symbs, - int16_t* g_bits, - uint32_t* inteleaver_lut); + uint32_t Qm, + uint32_t H_prime_total, + uint32_t N_pusch_symbs, + int16_t* g_bits, + uint32_t* inteleaver_lut); #endif // SRSLTE_SCH_H \ No newline at end of file diff --git a/lib/include/srslte/phy/phch/sci.h b/lib/include/srslte/phy/phch/sci.h new file mode 100644 index 000000000..03201f313 --- /dev/null +++ b/lib/include/srslte/phy/phch/sci.h @@ -0,0 +1,103 @@ +/* + * 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_SCI_H +#define SRSLTE_SCI_H + +#include +#include + +#include "srslte/config.h" +#include "srslte/phy/common/phy_common.h" + +#define SRSLTE_SCI_MSG_MAX_LEN 80 + +/** + * Sidelink Control Information - Sidelink (SCI0 and SCI1). + * + * \brief SCI0/1 packing/unpacking functions to convert between bit streams + * + * Reference: 3GPP TS 36.212 version 15.6.0 Release 15 Section 5.4.3 + */ +typedef struct SRSLTE_API { + + srslte_sl_tm_t tm; + uint32_t sci_len; + uint32_t nof_prb; + + srslte_sci_format_t format; + + // sizeSubChannel + uint32_t size_sub_channel; + + // numSubChannel + uint32_t num_sub_channel; + + ///< SCI Format 0: Resource block assignment and hopping resource allocation + ///< SCI Format 1: Frequency resource location (0,3,6,7,8 bits) + uint32_t riv; + + // Modulation and coding scheme (bits); + uint32_t mcs_idx; + + ///< SCI Format 0 + // Frequency hopping flag (1 bit) + bool freq_hopping_flag; + + uint32_t hopping_bits; + + // TRP - Time resource pattern (7bits) + uint32_t trp_idx; + + // Timing advance indication (11 bits) + uint32_t timing_advance; + + // Group ID (8 bits) + uint32_t N_sa_id; + + ///< SCI Format 1 + // Priority (3bits) + uint32_t priority; + + // Resource reservation (4 bits) + uint32_t resource_reserv; + + // Time gap (4 bits) + uint32_t time_gap; + + // Retransmission index (1 bit) + bool retransmission; + +} srslte_sci_t; + +SRSLTE_API int srslte_sci_init(srslte_sci_t* q, + uint32_t nof_prb, + srslte_sl_tm_t tm, + uint32_t size_sub_channel, + uint32_t num_sub_channel); +SRSLTE_API int srslte_sci_format0_pack(srslte_sci_t* q, uint8_t* output); +SRSLTE_API int srslte_sci_format1_pack(srslte_sci_t* q, uint8_t* output); +SRSLTE_API int srslte_sci_format0_unpack(srslte_sci_t* q, uint8_t* input); +SRSLTE_API int srslte_sci_format1_unpack(srslte_sci_t* q, uint8_t* input); +SRSLTE_API void srslte_sci_info(char* str, srslte_sci_t* q); +SRSLTE_API void srslte_sci_free(srslte_sci_t* q); + +#endif // SRSLTE_SCI_H diff --git a/lib/include/srslte/phy/sync/cfo.h b/lib/include/srslte/phy/sync/cfo.h index d6b04a711..c21c8b49d 100644 --- a/lib/include/srslte/phy/sync/cfo.h +++ b/lib/include/srslte/phy/sync/cfo.h @@ -34,6 +34,7 @@ #include "srslte/config.h" #include "srslte/phy/utils/cexptab.h" +#include "srslte/phy/common/phy_common.h" #define SRSLTE_CFO_CEXPTAB_SIZE 4096 @@ -61,4 +62,6 @@ srslte_cfo_correct_offset(srslte_cfo_t* h, const cf_t* input, cf_t* output, floa SRSLTE_API float srslte_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb); +SRSLTE_API float srslte_sl_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb, srslte_cp_t cp); + #endif // SRSLTE_CFO_H diff --git a/lib/src/phy/ch_estimation/chest_sl.c b/lib/src/phy/ch_estimation/chest_sl.c index eff2dd51f..534dcb14e 100644 --- a/lib/src/phy/ch_estimation/chest_sl.c +++ b/lib/src/phy/ch_estimation/chest_sl.c @@ -24,14 +24,13 @@ #include #include #include -#include -#include "srslte/phy/ch_estimation/chest_sl.h" + #include "srslte/phy/ch_estimation/chest_sl.h" #include "srslte/phy/mimo/precoding.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" #include "ul_rs_tables.h" -int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q, uint32_t N_sa_id) +int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q) { srslte_interp_linear_vector_init(&q->lin_vec_sl, SRSLTE_MAX_PRB * SRSLTE_NRE); @@ -61,12 +60,11 @@ int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q, uint32_t N_sa_id) } } - q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS_SYMB); // MAX PERIOD LENGTH 320 + q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * SRSLTE_SL_MAX_DMRS_PERIOD_LENGTH); // 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) { @@ -97,7 +95,8 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, uint32_t sf_idx, uint32_t N_sl_id, uint32_t L_crb, - uint32_t N_sa_id) + uint32_t N_x_id, + uint32_t cyclic_shift) { // M_sc_rs - Reference Signal Length switch (ch) { @@ -130,7 +129,7 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, 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->nof_dmrs_symbols = SRSLTE_SL_TM34_DEFAULT_NUM_DMRS_SYMBOLS; } } @@ -149,22 +148,19 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, } } 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; + q->n_CS[i] = cyclic_shift; } } 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; + q->n_CS[i] = (int)(N_x_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; + q->n_CS[i] = (int)(N_x_id / 2) % 8; } } break; @@ -181,90 +177,92 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, } // Group Hopping + uint32_t f_gh; // Group Hopping Flag + uint32_t f_ss; + uint32_t u[SRSLTE_SL_MAX_DMRS_SYMB]; // Sequence Group Number + // 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; + f_gh = 0; + f_ss = (N_sl_id / 16) % SRSLTE_SL_N_RU_SEQ; + for (int ns = 0; ns < q->nof_dmrs_symbols; ns++) { + u[ns] = (f_gh + f_ss) % SRSLTE_SL_N_RU_SEQ; } break; case SRSLTE_SIDELINK_PSCCH: - q->f_gh = 0; + f_gh = 0; if (tm <= SRSLTE_SIDELINK_TM2) { - q->f_ss = 0; + f_ss = 0; } else { - q->f_ss = 8; + f_ss = 8; } - for (int i = 0; i < q->nof_dmrs_symbols; ++i) { - q->u[i] = (q->f_gh + q->f_ss) % 30; + for (int ns = 0; ns < q->nof_dmrs_symbols; ns++) { + u[ns] = (f_gh + f_ss) % SRSLTE_SL_N_RU_SEQ; } break; case SRSLTE_SIDELINK_PSSCH: + srslte_group_hopping_f_gh(q->f_gh_pattern, N_x_id); + if (tm <= SRSLTE_SIDELINK_TM2) { - q->f_gh = 1; - q->f_ss = N_sa_id % 30; + f_ss = N_x_id % SRSLTE_SL_N_RU_SEQ; 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; + for (uint32_t ns = 0; ns < q->nof_dmrs_symbols; ns++) { + f_gh = q->f_gh_pattern[ns]; + u[ns] = (f_gh + f_ss + delta_ss) % SRSLTE_SL_N_RU_SEQ; } } else { // TM3/4 - q->f_gh = 1; - q->f_ss = (N_sa_id / 16) % 30; + f_ss = (N_x_id / 16) % SRSLTE_SL_N_RU_SEQ; 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; + for (uint32_t ns = 0; ns < q->nof_dmrs_symbols; ns++) { + f_gh = q->f_gh_pattern[(2 * 2 * (sf_idx % 10)) + ns]; + u[ns] = (f_gh + f_ss + delta_ss) % SRSLTE_SL_N_RU_SEQ; } } 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; + f_gh = 0; + f_ss = 0; + for (int ns = 0; ns < q->nof_dmrs_symbols; ns++) { + u[ns] = (f_gh + f_ss) % SRSLTE_SL_N_RU_SEQ; } break; } // N_zc - Zadoff Chu Sequence Length - + int32_t N_zc = 0; // 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; + q->r[j][i] = phi_M_sc_12[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; + q->r[j][i] = phi_M_sc_24[u[j]][i] * M_PI / 4; } } break; default: - for (uint32_t i = SRSLTE_SL_NOF_PRIME_NUMBERS - 1; i > 0; i--) { + for (uint32_t i = NOF_PRIME_NUMBERS - 1; i > 0; i--) { if (prime_numbers[i] < q->M_sc_rs) { - q->N_zc = prime_numbers[i]; + 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; + q->q[j] = get_q(u[j], SRSLTE_SL_BASE_SEQUENCE_NUMBER, N_zc); + float n_sz = (float)N_zc; for (uint32_t i = 0; i < q->M_sc_rs; i++) { - float m = (float)(i % q->N_zc); + float m = (float)(i % N_zc); q->r[j][i] = -M_PI * q->q[j] * m * (m + 1) / n_sz; } } @@ -318,7 +316,7 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, break; case SRSLTE_SIDELINK_PSSCH: if (tm <= SRSLTE_SIDELINK_TM2) { - if (N_sa_id % 2 == 0) { + if (N_x_id % 2 == 0) { q->w[0] = 1; q->w[1] = 1; } else { @@ -327,7 +325,7 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, } } else { // TM3/4 - if (N_sa_id % 2 == 0) { + if (N_x_id % 2 == 0) { q->w[0] = 1; q->w[1] = 1; q->w[2] = 1; @@ -353,14 +351,15 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, return SRSLTE_SUCCESS; } + int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q) { - return srslte_chest_sl_init_dmrs(q, 0); + return srslte_chest_sl_init_dmrs(q); } int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t tm, uint32_t N_sl_id) { - return srslte_chest_sl_gen_dmrs(q, tm, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0); + return srslte_chest_sl_gen_dmrs(q, tm, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0, 0); } int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, @@ -540,6 +539,176 @@ int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q, return sample_pos; } +int srslte_chest_sl_init_pscch_dmrs(srslte_chest_sl_t* q) +{ + return srslte_chest_sl_init_dmrs(q); +} + +int srslte_chest_sl_gen_pscch_dmrs(srslte_chest_sl_t* q, uint32_t cyclic_shift, srslte_sl_tm_t tm) +{ + return srslte_chest_sl_gen_dmrs(q, tm, SRSLTE_SIDELINK_PSCCH, 0, 0, 0, 0, cyclic_shift); +} + +int srslte_chest_sl_put_pscch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer, + uint32_t prb_idx, + srslte_sl_tm_t tm, + uint32_t nof_prb, + srslte_cp_t cp) +{ + + uint32_t samplePos = 0; + uint32_t k = prb_idx * SRSLTE_NRE; + + // Mapping to physical resources + for (uint32_t i = 0; i < srslte_sl_get_num_symbols(tm, cp); i++) { + if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i, cp)) { + memcpy(&sf_buffer[k + i * nof_prb * SRSLTE_NRE], &q->r_sequence[samplePos][0], q->M_sc_rs * sizeof(cf_t)); + samplePos++; + } + } + + return SRSLTE_SUCCESS; +} + +static void interpolate_pilots_sl_pscch(srslte_interp_linsrslte_vec_t* q, + cf_t* ce, + uint32_t n_prb, + uint32_t prb_idx, + srslte_sl_tm_t tm, + srslte_cp_t cp) +{ + uint32_t l_idx = 0; + uint32_t L[SRSLTE_SL_MAX_DMRS_SYMB] = {}; + for (int i = 0; i < srslte_sl_get_num_symbols(tm, cp); i++) { + if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i, cp)) { + L[l_idx] = i; + l_idx++; + } + } + + uint32_t NL = 2 * SRSLTE_CP_NSYMB(cp); + uint32_t nre = n_prb * SRSLTE_NRE; + + srslte_interp_linear_vector_resize(q, nre); + + uint32_t ce_l1 = SRSLTE_RE_IDX(n_prb, L[0], 0 * SRSLTE_NRE); + uint32_t ce_l2 = SRSLTE_RE_IDX(n_prb, L[1], 0 * SRSLTE_NRE); + + if ((tm == SRSLTE_SIDELINK_TM1) || (tm == SRSLTE_SIDELINK_TM2)) { + srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L[1] - L[0]), L[0], false, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L[1] - L[0]), (L[1] - L[0]) - 1, true, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l1], &ce[ce_l2], &ce[ce_l2], &ce[ce_l2 + nre], (L[1] - L[0]), (NL - L[1]) - 1, true, nre); + } else { + uint32_t ce_l3 = SRSLTE_RE_IDX(n_prb, L[2], 0 * SRSLTE_NRE); + uint32_t ce_l4 = SRSLTE_RE_IDX(n_prb, L[3], 0 * SRSLTE_NRE); + srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L[1] - L[0]), L[0], false, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L[1] - L[0]), (L[1] - L[0]) - 1, true, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l2], &ce[ce_l3], NULL, &ce[ce_l2 + nre], (L[2] - L[1]), (L[2] - L[1]) - 1, true, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l3], &ce[ce_l4], NULL, &ce[ce_l3 + nre], (L[3] - L[2]), (L[3] - L[2]) - 1, true, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l3], &ce[ce_l4], &ce[ce_l4], &ce[ce_l4 + nre], (L[3] - L[2]), (NL - L[3]) - 1, true, nre); + } +} + +void srslte_chest_sl_pscch_ls_estimate_equalize(srslte_chest_sl_t* q, + cf_t* sf_buffer, + uint32_t prb_idx, + cf_t* sf_buffer_rx, + uint32_t nof_prb, + srslte_sl_tm_t tm, + srslte_cp_t cp) +{ + int sf_n_re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE * nof_prb * 2; + + // Get Pilot Estimates + // Use the known DMRS signal to compute least-squares estimates + bzero(q->ce, sizeof(cf_t) * sf_n_re); + + if ((tm == SRSLTE_SIDELINK_TM1) || (tm == SRSLTE_SIDELINK_TM2)) { + if (cp == SRSLTE_CP_NORM) { + srslte_vec_prod_conj_ccc(&sf_buffer[3 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[0][0], + &q->ce[3 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[10 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[1][0], + &q->ce[10 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + } else { + srslte_vec_prod_conj_ccc(&sf_buffer[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[0][0], + &q->ce[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[1][0], + &q->ce[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + } + } else if ((tm == SRSLTE_SIDELINK_TM3) || (tm == SRSLTE_SIDELINK_TM4)) { + if (cp == SRSLTE_CP_NORM) { + srslte_vec_prod_conj_ccc(&sf_buffer[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[0][0], + &q->ce[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[5 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[1][0], + &q->ce[5 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[2][0], + &q->ce[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[11 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + &q->r_sequence[3][0], + &q->ce[11 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE], + q->M_sc_rs); + } else { + ERROR("Invalid CP"); + return; + } + } else { + ERROR("Invalid TM"); + return; + } + + interpolate_pilots_sl_pscch(&q->lin_vec_sl, q->ce, nof_prb, prb_idx, tm, cp); + + // Perform channel equalization + srslte_predecoding_single(sf_buffer, q->ce, sf_buffer_rx, NULL, sf_n_re, 1, 0.0); +} + +int srslte_chest_sl_get_pscch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer_rx, + uint32_t prb_idx, + cf_t** dmrs_received, + srslte_sl_tm_t tm, + uint32_t nof_prb, + srslte_cp_t cp) +{ + uint32_t samplePos = 0; + uint32_t k = prb_idx * SRSLTE_NRE; + + // Get DMRSs + for (uint32_t i = 0; i < srslte_sl_get_num_symbols(tm, cp); i++) { + if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i, cp)) { + memcpy(&q->dmrs_received[samplePos][0], &sf_buffer_rx[k + i * nof_prb * SRSLTE_NRE], q->M_sc_rs * sizeof(cf_t)); + samplePos++; + } + } + + 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 SRSLTE_SUCCESS; +} + void srslte_chest_sl_free(srslte_chest_sl_t* q) { srslte_interp_linear_vector_free(&q->lin_vec_sl); diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index fa388308e..dbeac1c74 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -814,37 +814,57 @@ char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode) } ///< Sidelink helpers +int srslte_sl_get_num_symbols(srslte_sl_tm_t tm, srslte_cp_t cp) +{ + if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) { + if (cp == SRSLTE_CP_NORM) { + return SRSLTE_CP_NORM_SF_NSYMB; + } else { + return SRSLTE_CP_EXT_SF_NSYMB; + } + } else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) { + if (cp == SRSLTE_CP_NORM) { + return SRSLTE_CP_NORM_SF_NSYMB; + } else { + ERROR("Invalid CP"); + return SRSLTE_ERROR; + } + } else { + ERROR("Invalid TM"); + return SRSLTE_ERROR; + } +} ///< 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}; +static const 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}; + +static const 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) { @@ -897,3 +917,85 @@ srslte_ack_nack_feedback_mode_t srslte_string_ack_nack_feedback_mode(const char* // Otherwise Normal return SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL; } + +static const srslte_sl_symbol_t srslte_pscch_symbol_map_tm12[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_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_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_GUARD_SYMBOL}; + +static const srslte_sl_symbol_t srslte_pscch_symbol_map_tm12_ext[SRSLTE_CP_EXT_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_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_DMRS_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_GUARD_SYMBOL}; + +static const srslte_sl_symbol_t srslte_pscch_symbol_map_tm34[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_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_DATA_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_GUARD_SYMBOL}; + +bool srslte_pscch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i, srslte_cp_t cp) +{ + if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) { + if (cp == SRSLTE_CP_EXT) { + return srslte_pscch_symbol_map_tm12_ext[i] == type; + } + return srslte_pscch_symbol_map_tm12[i] == type; + } else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) { + return srslte_pscch_symbol_map_tm34[i] == type; + } + return false; +} + +uint32_t srslte_sci_format0_sizeof(uint32_t nof_prb) +{ + // 3GPP TS 36.212 5.4.3.1 + uint32_t n = 0; + + // Frequency hopping flag – 1 bit + n += 1; + + // Resource block assignment and hopping resource allocation + n += (uint32_t)ceil(log((nof_prb * (nof_prb + 1)) / 2.0) / log(2)); + + // Time resource pattern – 7 bits + n += 7; + + // Modulation and coding scheme – 5 bit + n += 5; + + // Timing advance indication – 11 bits + n += 11; + + // Group destination ID – 8 bits + n += 8; + + return n; +} \ No newline at end of file diff --git a/lib/src/phy/phch/pscch.c b/lib/src/phy/phch/pscch.c new file mode 100644 index 000000000..0d0bf0b3c --- /dev/null +++ b/lib/src/phy/phch/pscch.c @@ -0,0 +1,361 @@ +/* + * 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 +#include + +#include "srslte/phy/phch/pscch.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/scrambling/scrambling.h" + +int srslte_pscch_init(srslte_pscch_t* q, uint32_t nof_prb, srslte_sl_tm_t tm, srslte_cp_t cp) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = SRSLTE_ERROR; + + q->cp = cp; + q->tm = tm; + q->nof_prb = nof_prb; + + if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) { + q->sci_len = srslte_sci_format0_sizeof(nof_prb); + q->nof_symbols = SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS; + q->pscch_nof_prb = SRSLTE_PSCCH_TM12_NOF_PRB; + + if (cp == SRSLTE_CP_EXT) { + q->nof_symbols = SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS_EXT; + } + } else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) { + q->sci_len = SRSLTE_SCI_TM34_LEN; + q->nof_symbols = SRSLTE_PSCCH_TM34_NUM_DATA_SYMBOLS; + q->pscch_nof_prb = SRSLTE_PSCCH_TM34_NOF_PRB; + } else { + return SRSLTE_ERROR; + } + + // CRC + uint32_t crc_poly = 0x11021; + if (srslte_crc_init(&q->crc, crc_poly, SRSLTE_SCI_CRC_LEN)) { + return SRSLTE_ERROR; + } + q->c = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN); + if (!q->c) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->sci_crc = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SCI_CRC_LEN); + if (!q->sci_crc) { + 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)); + q->d = srslte_vec_malloc(sizeof(uint8_t) * (3 * (SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN))); + if (!q->d) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + bzero(q->d, sizeof(uint8_t) * (3 * (SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN))); + + q->d_16 = srslte_vec_malloc(sizeof(int16_t) * (3 * (SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN))); + if (!q->d_16) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + srslte_viterbi_init( + &q->dec, SRSLTE_VITERBI_37, q->encoder.poly, SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN, q->encoder.tail_biting); + + q->E = SRSLTE_NRE * q->nof_symbols * q->pscch_nof_prb * SRSLTE_PSCCH_QM; + q->e = srslte_vec_malloc(sizeof(uint8_t) * q->E); + if (!q->e) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->e_16 = srslte_vec_malloc(sizeof(int16_t) * q->E); + if (!q->e_16) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->e_bytes = srslte_vec_malloc(sizeof(uint8_t) * q->E / 8); + if (!q->e_bytes) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + q->interleaver_lut = srslte_vec_malloc(sizeof(uint32_t) * q->E); + if (!q->interleaver_lut) { + ERROR("Error allocating memory\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; + } + q->codeword_bytes = srslte_vec_malloc(sizeof(uint8_t) * q->E / 8); + if (!q->codeword_bytes) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Scrambling + bzero(&q->seq, sizeof(srslte_sequence_t)); + srslte_sequence_LTE_pr(&q->seq, q->E, SRSLTE_PSCCH_SCRAMBLING_SEED); + + // Modulation + if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { + return SRSLTE_ERROR; + } + + q->mod_symbols = srslte_vec_malloc(sizeof(cf_t) * q->E / SRSLTE_PSCCH_QM); + 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; + } + + // DFT Precoding + if (srslte_dft_precoding_init(&q->dft_precoder, q->nof_prb, true)) { + return SRSLTE_ERROR; + } + q->scfdma_symbols = srslte_vec_malloc(sizeof(cf_t) * q->E / SRSLTE_PSCCH_QM); + if (!q->scfdma_symbols) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // IDFT Predecoding + if (srslte_dft_precoding_init(&q->idft_precoder, q->pscch_nof_prb, false)) { + return SRSLTE_ERROR; + } + + q->nof_tx_re = (q->nof_symbols - 1) * SRSLTE_NRE * q->pscch_nof_prb; // Last OFDM symbol is used channel processing but not transmitted + + ret = SRSLTE_SUCCESS; + } + + return ret; +} + +int srslte_pscch_encode(srslte_pscch_t* q, uint8_t* sci, cf_t* sf_buffer, uint32_t prb_idx) +{ + memcpy(q->c, sci, sizeof(uint8_t) * q->sci_len); + + // CRC Attachment + srslte_crc_attach(&q->crc, q->c, q->sci_len); + + // Channel Coding + srslte_convcoder_encode(&q->encoder, q->c, q->d, q->sci_len + SRSLTE_SCI_CRC_LEN); + + // Rate Matching + if (srslte_rm_conv_tx(q->d, (3 * (q->sci_len + SRSLTE_SCI_CRC_LEN)), q->e, q->E)) { + return SRSLTE_ERROR; + } + + // Interleaving + srslte_bit_pack_vector(q->e, q->e_bytes, q->E); + srslte_sl_ulsch_interleave(q->e_bytes, // input bytes + SRSLTE_PSCCH_QM, // modulation + q->E / SRSLTE_PSCCH_QM, // prime number + q->nof_symbols, // nof pscch symbols + q->codeword_bytes // output + ); + srslte_bit_unpack_vector(q->codeword_bytes, q->codeword, q->E); + + // Scrambling + srslte_scrambling_b(&q->seq, q->codeword); + + // Modulation + srslte_mod_modulate(&q->mod, q->codeword, q->mod_symbols, q->E); + + // Layer Mapping + // Void: Single layer + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.3 + + // DFT Precoding + srslte_dft_precoding(&q->dft_precoder, q->mod_symbols, q->scfdma_symbols, q->pscch_nof_prb, q->nof_symbols); + + // Precoding + // Void: Single antenna port + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.5 + + if (srslte_pscch_put(q, sf_buffer, prb_idx) != q->nof_tx_re) { + printf("Error during PSCCH RE mapping\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_pscch_decode(srslte_pscch_t* q, cf_t* equalized_sf_syms, uint8_t* sci, uint32_t prb_idx) +{ + if (srslte_pscch_get(q, equalized_sf_syms, prb_idx) != q->nof_tx_re) { + printf("Error during PSCCH RE extraction\n"); + return SRSLTE_ERROR; + } + + // Precoding + // Void: Single antenna port + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.5 + + // IDFT Precoding + srslte_dft_precoding(&q->idft_precoder, q->scfdma_symbols, q->mod_symbols, q->pscch_nof_prb, q->nof_symbols); + + // Layer Mapping + // Void: Single layer + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.3 + + // Demodulation + srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->mod_symbols, q->llr, q->E / SRSLTE_PSCCH_QM); + + // Descrambling + srslte_scrambling_s(&q->seq, q->llr); + + // Deinterleaving + srslte_sl_ulsch_deinterleave( + q->llr, SRSLTE_PSCCH_QM, q->E / SRSLTE_PSCCH_QM, q->nof_symbols, q->e_16, q->interleaver_lut); + + // Rate matching + srslte_rm_conv_rx_s(q->e_16, q->E, q->d_16, (3 * (q->sci_len + SRSLTE_SCI_CRC_LEN))); + + // Channel decoding + srslte_viterbi_decode_s(&q->dec, q->d_16, q->c, q->sci_len + SRSLTE_SCI_CRC_LEN); + + // Copy received crc + memcpy(q->sci_crc, &q->c[q->sci_len], sizeof(uint8_t) * SRSLTE_SCI_CRC_LEN); + + // Re-attach crc + srslte_crc_attach(&q->crc, q->c, q->sci_len); + + // CRC check + if (srslte_bit_diff(q->sci_crc, &q->c[q->sci_len], SRSLTE_SCI_CRC_LEN) != 0) { + return SRSLTE_ERROR; + } + + // Remove CRC and copy content to sci buffer + memcpy(sci, q->c, sizeof(uint8_t) * q->sci_len); + + return SRSLTE_SUCCESS; +} + +int srslte_pscch_put(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx) +{ + int sample_pos = 0; + int k = prb_idx * SRSLTE_NRE; + for (int i = 0; i < srslte_sl_get_num_symbols(q->tm, q->cp); ++i) { + if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i, q->cp)) { + memcpy(&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE], + &q->scfdma_symbols[sample_pos], + sizeof(cf_t) * (SRSLTE_NRE * q->pscch_nof_prb)); + sample_pos += (SRSLTE_NRE * q->pscch_nof_prb); + } + } + return sample_pos; +} + +int srslte_pscch_get(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx) +{ + int sample_pos = 0; + int k = prb_idx * SRSLTE_NRE; + for (int i = 0; i < srslte_sl_get_num_symbols(q->tm, q->cp); ++i) { + if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i, q->cp)) { + memcpy(&q->scfdma_symbols[sample_pos], + &sf_buffer[k + i * q->nof_prb * SRSLTE_NRE], + sizeof(cf_t) * (SRSLTE_NRE * q->pscch_nof_prb)); + sample_pos += (SRSLTE_NRE * q->pscch_nof_prb); + } + } + + return sample_pos; +} + +void srslte_pscch_free(srslte_pscch_t* q) +{ + if (q != NULL) { + 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->sci_crc) { + free(q->sci_crc); + } + if (q->c) { + free(q->c); + } + if (q->d) { + free(q->d); + } + if (q->d_16) { + free(q->d_16); + } + if (q->e) { + free(q->e); + } + if (q->e_16) { + free(q->e_16); + } + if (q->e_bytes) { + free(q->e_bytes); + } + if (q->interleaver_lut) { + free(q->interleaver_lut); + } + if (q->codeword) { + free(q->codeword); + } + if (q->codeword_bytes) { + free(q->codeword_bytes); + } + 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_pscch_t)); + } +} diff --git a/lib/src/phy/phch/sci.c b/lib/src/phy/phch/sci.c new file mode 100644 index 000000000..0008ef2f8 --- /dev/null +++ b/lib/src/phy/phch/sci.c @@ -0,0 +1,170 @@ +/* + * 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 +#include "srslte/phy/phch/sci.h" +#include "srslte/phy/utils/bit.h" + +int srslte_sci_init(srslte_sci_t* q, + uint32_t nof_prb, + srslte_sl_tm_t tm, + uint32_t size_sub_channel, + uint32_t num_sub_channel) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL) { + ret = SRSLTE_ERROR; + + bzero(q, sizeof(srslte_sci_t)); + + q->nof_prb = nof_prb; + q->tm = tm; + + if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) { + q->format = SRSLTE_SCI_FORMAT0; + q->sci_len = srslte_sci_format0_sizeof(nof_prb); + + } else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) { + q->format = SRSLTE_SCI_FORMAT1; + q->sci_len = SRSLTE_SCI_TM34_LEN; + q->size_sub_channel = size_sub_channel; + q->num_sub_channel = num_sub_channel; + + } else { + return SRSLTE_ERROR; + } + ret = SRSLTE_SUCCESS; + } + + return ret; +} + +int srslte_sci_format0_pack(srslte_sci_t* q, uint8_t* output) +{ + if (!q) { + printf("Error packing SCI Format 0\n"); + return SRSLTE_ERROR; + } + + bzero(output, sizeof(uint8_t) * SRSLTE_SCI_MAX_LEN); + srslte_bit_unpack((uint32_t)q->freq_hopping_flag, &output, 1); + if (q->freq_hopping_flag) { + printf("Frequency Hopping in Sidelink is not supported\n"); + return SRSLTE_ERROR; + } else { + srslte_bit_unpack(q->riv, &output, (uint32_t)ceil(log2(((q->nof_prb) * (q->nof_prb + 1) / 2)))); + } + srslte_bit_unpack(q->trp_idx, &output, 7); + srslte_bit_unpack(q->mcs_idx, &output, 5); + srslte_bit_unpack(q->timing_advance, &output, 11); + srslte_bit_unpack(q->N_sa_id, &output, 8); + + return SRSLTE_SUCCESS; +} + +int srslte_sci_format1_pack(srslte_sci_t* q, uint8_t* output) +{ + if (!q) { + printf("Error packing SCI Format 1\n"); + return SRSLTE_ERROR; + } + + bzero(output, sizeof(uint8_t) * SRSLTE_SCI_MAX_LEN); + srslte_bit_unpack(q->priority, &output, 3); + srslte_bit_unpack(q->resource_reserv, &output, 4); + srslte_bit_unpack(q->riv, &output, (uint32_t)ceil(log2(((q->num_sub_channel) * (q->num_sub_channel + 1) / 2)))); + srslte_bit_unpack(q->time_gap, &output, 4); + srslte_bit_unpack(q->mcs_idx, &output, 5); + srslte_bit_unpack(q->retransmission, &output, 1); + + return SRSLTE_SUCCESS; +} + +int srslte_sci_format0_unpack(srslte_sci_t* q, uint8_t* input) +{ + if (!q) { + printf("Error unpacking SCI Format 0\n"); + return SRSLTE_ERROR; + } + + q->freq_hopping_flag = (bool)srslte_bit_pack(&input, 1); + if (q->freq_hopping_flag) { + printf("Frequency Hopping in Sidelink is not supported\n"); + return SRSLTE_ERROR; + } else { + q->riv = srslte_bit_pack(&input, (uint32_t)ceil(log2(((q->nof_prb) * (q->nof_prb + 1) / 2)))); + } + q->trp_idx = srslte_bit_pack(&input, 7); + q->mcs_idx = srslte_bit_pack(&input, 5); + q->timing_advance = srslte_bit_pack(&input, 11); + q->N_sa_id = srslte_bit_pack(&input, 8); + + return SRSLTE_SUCCESS; +} + +int srslte_sci_format1_unpack(srslte_sci_t* q, uint8_t* input) +{ + if (!q) { + printf("Error unpacking SCI Format 1\n"); + return SRSLTE_ERROR; + } + + q->priority = srslte_bit_pack(&input, 3); + q->resource_reserv = srslte_bit_pack(&input, 4); + q->riv = srslte_bit_pack(&input, (uint32_t)ceil(log2(((q->num_sub_channel) * (q->num_sub_channel + 1) / 2)))); + q->time_gap = srslte_bit_pack(&input, 4); + q->mcs_idx = srslte_bit_pack(&input, 5); + q->retransmission = srslte_bit_pack(&input, 1); + + return SRSLTE_SUCCESS; +} + +void srslte_sci_info(char* str, srslte_sci_t* q) +{ + uint32_t n = snprintf(str, 20, "SCI%i: riv=%i, mcs=%i", q->format, q->riv, q->mcs_idx); + + if (q->format == SRSLTE_SCI_FORMAT0) { + n = srslte_print_check(str, + SRSLTE_SCI_MSG_MAX_LEN, + n, + ", trp_idx=%i, t_adv=%i, n_sa_id=%i, freqhoppflg=%s\n", + q->trp_idx, + q->timing_advance, + q->N_sa_id, + q->freq_hopping_flag ? "true" : "false"); + } else if (q->format == SRSLTE_SCI_FORMAT1) { + n = srslte_print_check(str, + SRSLTE_SCI_MSG_MAX_LEN, + n, + ", priority=%i, res_rsrv=%i, t_gap=%i, rtx=%i\n", + q->priority, + q->resource_reserv, + q->time_gap, + q->retransmission); + } +} + +void srslte_sci_free(srslte_sci_t* q) +{ + if (q != NULL) { + bzero(q, sizeof(srslte_sci_t)); + } +} \ No newline at end of file diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index c18b18861..1a5c56cde 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -53,15 +53,75 @@ 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 -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) +add_test(psbch_file_test_ideal_tm2_p6_c0 psbch_file_test -p 6 -t 2 -c 0 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat) +add_test(psbch_file_test_ideal_tm2_p15_c84 psbch_file_test -p 15 -t 2 -c 84 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat) +add_test(psbch_file_test_ideal_tm2_p25_c168 psbch_file_test -p 25 -t 2 -c 168 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat) +add_test(psbch_file_test_ideal_tm2_p50_c252 psbch_file_test -p 50 -t 2 -c 252 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat) +add_test(psbch_file_test_ideal_tm2_p100_c335 psbch_file_test -p 100 -t 2 -c 335 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat) # TM4 file tests add_test(psbch_file_test_cmw_tm4_p50_c169 psbch_file_test -p 50 -c 169 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_slss_id169.dat) +######################################################################## +# PSCCH TEST +######################################################################## + +add_executable(pscch_test pscch_test.c) +target_link_libraries(pscch_test srslte_phy) + +# TM2 self tests +add_test(pscch_test_tm2_p6 pscch_test -p 6) +add_test(pscch_test_tm2_p15 pscch_test -p 15) +add_test(pscch_test_tm2_p25 pscch_test -p 25) +add_test(pscch_test_tm2_p50 pscch_test -p 50) +add_test(pscch_test_tm2_p75 pscch_test -p 75) +add_test(pscch_test_tm2_p100 pscch_test -p 100) + +# TM4 self tests +add_test(pscch_test_tm4_p6 pscch_test -p 6 -t 4) +add_test(pscch_test_tm4_p15 pscch_test -p 15 -t 4) +add_test(pscch_test_tm4_p25 pscch_test -p 25 -t 4) +add_test(pscch_test_tm4_p50 pscch_test -p 50 -t 4) +add_test(pscch_test_tm4_p75 pscch_test -p 75 -t 4) +add_test(pscch_test_tm4_p100 pscch_test -p 100 -t 4) + +add_executable(pscch_file_test pscch_file_test.c) +target_link_libraries(pscch_file_test srslte_phy) + +# TM2 file tests +add_test(pscch_file_test_ideal_tm2_p100 pscch_file_test -p 100 -t 2 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat) +set_property(TEST pscch_file_test_ideal_tm2_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2") + +# TM4 file tests +add_test(pscch_file_test_ideal_tm4_p100 pscch_file_test -p 100 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat) +set_property(TEST pscch_file_test_ideal_tm4_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1") + +add_test(pscch_test_tm4_p50_qc pscch_file_test -p 50 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat) +set_property(TEST pscch_test_tm4_p50_qc PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1") + +add_test(pscch_test_tm4_p50_cmw pscch_file_test -p 50 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat) +set_property(TEST pscch_test_tm4_p50_cmw PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1") + +# With PHY retransmission (3 TTI offset) +add_test(pscch_test_tm4_p50_huawei pscch_file_test -p 50 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat) +set_property(TEST pscch_test_tm4_p50_huawei PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2") + +# With PHY ReTx (0 TTI offset?) +add_test(pscch_test_tm4_p50_uxm1 pscch_file_test -p 50 -d -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat) +set_property(TEST pscch_test_tm4_p50_uxm1 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2") + +# 100 PRB startOffset 1 MCS12 MAC padding +add_test(pscch_test_tm4_p100_uxm2 pscch_file_test -p 100 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat) +set_property(TEST pscch_test_tm4_p100_uxm2 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=4") + +# 100 PRB LTE sampling rate, startOffset1 MCS12 ITS data +add_test(pscch_test_tm4_p100_uxm3 pscch_file_test -p 100 -d -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat) +set_property(TEST pscch_test_tm4_p100_uxm3 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1") + +# 50 PRB LTE sampling rate, startOffset0 MCS28 MAC padding +add_test(pscch_test_tm4_p50_uxm4 pscch_file_test -p 50 -d -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat) +set_property(TEST pscch_test_tm4_p50_uxm4 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=5") + ######################################################################## # NPBCH TEST ######################################################################## diff --git a/lib/src/phy/phch/test/pscch_file_test.c b/lib/src/phy/phch/test/pscch_file_test.c new file mode 100644 index 000000000..d3aa3199e --- /dev/null +++ b/lib/src/phy/phch/test/pscch_file_test.c @@ -0,0 +1,319 @@ +/* + * 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 +#include +#include +#include +#include + +#include "srslte/phy/ch_estimation/chest_sl.h" +#include "srslte/phy/channel/ch_awgn.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/io/filesource.h" +#include "srslte/phy/phch/pscch.h" +#include "srslte/phy/phch/sci.h" +#include "srslte/phy/sync/cfo.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" + +char* input_file_name; +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 size_sub_channel = 10; +uint32_t num_sub_channel = 5; +uint32_t file_offset = 0; + +uint32_t sf_n_samples; +uint32_t sf_n_re; +cf_t* sf_buffer; +cf_t* equalized_sf_buffer; +cf_t* input_buffer; +srslte_sci_t sci; +srslte_pscch_t pscch; +srslte_chest_sl_t pscch_chest; +srslte_ofdm_t fft; + +srslte_filesource_t fsrc; + +void usage(char* prog) +{ + printf("Usage: %s [deioptxzn]\n", prog); + printf("\t-i input_file_name\n"); + printf("\t-o File offset samples [Default %d]\n", file_offset); + 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-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (tm + 1)); + printf("\t-z Size of sub-channels [Default %i]\n", size_sub_channel); + printf("\t-n Number of sub-channels [Default %i]\n", num_sub_channel); + 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, "deioptznv")) != -1) { + switch (opt) { + case 'd': + use_standard_lte_rates = true; + break; + case 'o': + file_offset = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'e': + cp = SRSLTE_CP_EXT; + break; + case 'i': + input_file_name = argv[optind]; + break; + case 'p': + nof_prb = (int32_t)strtol(argv[optind], NULL, 10); + break; + case 't': + switch ((int32_t)strtol(argv[optind], NULL, 10)) { + 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 'z': + size_sub_channel = (int32_t)strtol(argv[optind], NULL, 10); + break; + case 'n': + num_sub_channel = (int32_t)strtol(argv[optind], NULL, 10); + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int base_init() +{ + sf_n_samples = srslte_symbol_sz(nof_prb) * 15; + + sf_n_re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE * 2 * nof_prb; + + sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); + if (!sf_buffer) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + equalized_sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); + if (!equalized_sf_buffer) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + input_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); + if (!input_buffer) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + srslte_sci_init(&sci, nof_prb, tm, size_sub_channel, num_sub_channel); + + if (srslte_pscch_init(&pscch, nof_prb, tm, cp) != SRSLTE_SUCCESS) { + ERROR("Error in PSCCH init\n"); + return SRSLTE_ERROR; + } + + if (srslte_chest_sl_init_pscch_dmrs(&pscch_chest) != SRSLTE_SUCCESS) { + ERROR("Error in PSCCH DMRS init\n"); + return SRSLTE_ERROR; + } + + 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 { + ERROR("Invalid input file name\n"); + return SRSLTE_ERROR; + } + + 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); + + return SRSLTE_SUCCESS; +} + +void base_free() +{ + srslte_filesource_free(&fsrc); + srslte_ofdm_rx_free(&fft); + + srslte_sci_free(&sci); + srslte_pscch_free(&pscch); + srslte_chest_sl_free(&pscch_chest); + + if (sf_buffer) { + free(sf_buffer); + } + if (equalized_sf_buffer) { + free(equalized_sf_buffer); + } + if (input_buffer) { + free(input_buffer); + } +} + +int main(int argc, char** argv) +{ + uint8_t sci_rx[SRSLTE_SCI_MAX_LEN] = {}; + int ret = SRSLTE_ERROR; + + parse_args(argc, argv); + srslte_use_standard_symbol_size(use_standard_lte_rates); + + if (base_init()) { + ERROR("Error initializing\n"); + base_free(); + return SRSLTE_ERROR; + } + + uint32_t num_decoded_sci = 0; + char sci_msg[SRSLTE_SCI_MSG_MAX_LEN] = ""; + + int max_num_subframes = 128; + int num_subframes = 0; + int nread = 0; + + if (file_offset > 0) { + printf("Offsetting file by %d samples.\n", file_offset); + srslte_filesource_seek(&fsrc, file_offset * sizeof(cf_t)); + } + + do { + nread = srslte_filesource_read(&fsrc, input_buffer, sf_n_samples); + if (nread < 0) { + fprintf(stderr, "Error reading from file\n"); + return ret; + } else if (nread == 0) { + goto clean_exit; + } else if (nread < sf_n_samples) { + fprintf(stderr, "Couldn't read entire subframe. Still processing ..\n"); + nread = -1; + } + + // CFO estimation and correction + srslte_sl_cfo_est_corr_cp(input_buffer, nof_prb, cp); + srslte_ofdm_rx_sf(&fft); + + if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) { + uint32_t prb_num = (uint32_t)ceil(nof_prb / 2); + uint32_t prb_start = 0; + uint32_t prb_end = nof_prb - 1; + uint32_t cyclic_shift = 0; + + srslte_chest_sl_gen_pscch_dmrs(&pscch_chest, cyclic_shift, tm); + + for (uint32_t pscch_prb_idx = prb_start; pscch_prb_idx <= prb_end; pscch_prb_idx++) { + if (pscch_prb_idx == (prb_start + prb_num)) { + pscch_prb_idx = (prb_end + 1) - prb_num; + } + + // PSCCH Channel estimation + srslte_chest_sl_pscch_ls_estimate_equalize( + &pscch_chest, sf_buffer, pscch_prb_idx, equalized_sf_buffer, nof_prb, tm, cp); + + if (srslte_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_idx) == SRSLTE_SUCCESS) { + if (srslte_sci_format0_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) { + printf("Error unpacking sci format 0\n"); + return SRSLTE_ERROR; + } + + srslte_sci_info(sci_msg, &sci); + fprintf(stdout, "%s", sci_msg); + + num_decoded_sci++; + } + } + } else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) { + for (int i = 0; i < num_sub_channel; i++) { + uint32_t pscch_prb_idx = size_sub_channel * i; + + for (uint32_t cyclic_shift = 0; cyclic_shift <= 9; cyclic_shift += 3) { + // PSCCH Channel estimation + srslte_chest_sl_gen_pscch_dmrs(&pscch_chest, cyclic_shift, tm); + srslte_chest_sl_pscch_ls_estimate_equalize( + &pscch_chest, sf_buffer, pscch_prb_idx, equalized_sf_buffer, nof_prb, tm, cp); + + if (srslte_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_idx) == SRSLTE_SUCCESS) { + if (srslte_sci_format1_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) { + printf("Error unpacking sci format 1\n"); + return SRSLTE_ERROR; + } + + srslte_sci_info(sci_msg, &sci); + fprintf(stdout, "%s", sci_msg); + + num_decoded_sci++; + } + if (SRSLTE_VERBOSE_ISDEBUG()) { + char filename[64]; + snprintf( + filename, 64, "pscch_rx_syms_sf%d_shift%d_prbidx%d.bin", num_subframes, cyclic_shift, pscch_prb_idx); + printf("Saving PSCCH symbols (%d) to %s\n", pscch.E / SRSLTE_PSCCH_QM, filename); + srslte_vec_save_file(filename, pscch.mod_symbols, pscch.E / SRSLTE_PSCCH_QM * sizeof(cf_t)); + } + } + } + } + num_subframes++; + } while (nread > 0 && num_subframes < max_num_subframes); + +clean_exit: + + base_free(); + + printf("num_decoded_sci=%d\n", num_decoded_sci); + + ret = (num_decoded_sci > 0) ? SRSLTE_SUCCESS : SRSLTE_ERROR; + + return ret; +} diff --git a/lib/src/phy/phch/test/pscch_test.c b/lib/src/phy/phch/test/pscch_test.c new file mode 100644 index 000000000..58241943f --- /dev/null +++ b/lib/src/phy/phch/test/pscch_test.c @@ -0,0 +1,169 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "srslte/phy/phch/pscch.h" +#include "srslte/phy/phch/sci.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" + +int32_t N_sl_id = 168; +uint32_t nof_prb = 6; +srslte_cp_t cp = SRSLTE_CP_NORM; +srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2; + +uint32_t size_sub_channel = 10; +uint32_t num_sub_channel = 5; + +uint32_t prb_idx = 0; + +void usage(char* prog) +{ + printf("Usage: %s [cdeipt]\n", prog); + printf("\t-p nof_prb [Default %d]\n", nof_prb); + 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, "ceiptv")) != -1) { + switch (opt) { + case 'c': + N_sl_id = (int32_t)strtol(argv[optind], NULL, 10); + break; + case 'p': + nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 't': + switch (strtol(argv[optind], NULL, 10)) { + 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); + + char sci_msg[SRSLTE_SCI_MSG_MAX_LEN] = ""; + + 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); + + // SCI + srslte_sci_t sci; + srslte_sci_init(&sci, nof_prb, tm, size_sub_channel, num_sub_channel); + + // PSCCH + srslte_pscch_t pscch; + if (srslte_pscch_init(&pscch, nof_prb, tm, cp) != SRSLTE_SUCCESS) { + ERROR("Error in PSCCH init\n"); + return SRSLTE_ERROR; + } + + // SCI message bits + uint8_t sci_tx[SRSLTE_SCI_MAX_LEN] = {}; + if (sci.format == SRSLTE_SCI_FORMAT0) { + if (srslte_sci_format0_pack(&sci, sci_tx) != SRSLTE_SUCCESS) { + printf("Error packing sci format 0\n"); + return SRSLTE_ERROR; + } + } else if (sci.format == SRSLTE_SCI_FORMAT1) { + if (srslte_sci_format1_pack(&sci, sci_tx) != SRSLTE_SUCCESS) { + printf("Error packing sci format 1\n"); + return SRSLTE_ERROR; + } + } + + printf("Tx payload: "); + srslte_vec_fprint_hex(stdout, sci_tx, sci.sci_len); + + // Put SCI into PSCCH + srslte_pscch_encode(&pscch, sci_tx, sf_buffer, prb_idx); + + // Prepare Rx buffer + uint8_t sci_rx[SRSLTE_SCI_MAX_LEN] = {}; + + // Decode PSCCH + if (srslte_pscch_decode(&pscch, sf_buffer, sci_rx, prb_idx) == SRSLTE_SUCCESS) { + printf("Rx payload: "); + srslte_vec_fprint_hex(stdout, sci_rx, sci.sci_len); + + uint32_t riv_txed = sci.riv; + if (sci.format == SRSLTE_SCI_FORMAT0) { + if (srslte_sci_format0_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) { + printf("Error unpacking sci format 0\n"); + return SRSLTE_ERROR; + } + } else if (sci.format == SRSLTE_SCI_FORMAT1) { + if (srslte_sci_format1_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) { + printf("Error unpacking sci format 1\n"); + return SRSLTE_ERROR; + } + } + + srslte_sci_info(sci_msg, &sci); + fprintf(stdout, "%s", sci_msg); + if (sci.riv == riv_txed) { + ret = SRSLTE_SUCCESS; + } + } + + free(sf_buffer); + srslte_sci_free(&sci); + srslte_pscch_free(&pscch); + + return ret; +} \ No newline at end of file diff --git a/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat b/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat new file mode 100755 index 000000000..d4dde15d6 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat b/lib/src/phy/phch/test/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat new file mode 100644 index 000000000..5b31831c8 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e+6.dat deleted file mode 100644 index e71e92801..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat new file mode 100644 index 000000000..9ef2d87e9 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat new file mode 100644 index 000000000..2a85e8a0e Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat deleted file mode 100644 index 4cc0aad40..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat new file mode 100644 index 000000000..c242cedb3 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e+6.dat deleted file mode 100644 index 32d75340d..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat new file mode 100644 index 000000000..516f8e9aa Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat new file mode 100644 index 000000000..77e801ba4 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_s30.72e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_s30.72e+6.dat deleted file mode 100644 index 5ea16c96d..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_s30.72e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat similarity index 64% rename from lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e+6.dat rename to lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat index 1520ac0a7..8ce804091 100644 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e+6.dat and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_s3.84e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_s3.84e+6.dat deleted file mode 100644 index 50f307720..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_s3.84e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_size5_num3_cshift0_s3.84e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_size5_num3_cshift0_s3.84e6.dat new file mode 100644 index 000000000..2ba7bf5aa Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_size5_num3_cshift0_s3.84e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_s7.68e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_s7.68e+6.dat deleted file mode 100644 index e3ab734ca..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_s7.68e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_size5_num5_cshift0_s7.68e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_size5_num5_cshift0_s7.68e6.dat new file mode 100644 index 000000000..fe084a824 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_size5_num5_cshift0_s7.68e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_s15.36e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_s15.36e+6.dat deleted file mode 100644 index c9b8bf502..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_s15.36e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_size10_num5_cshift0_s15.36e6.dat similarity index 63% rename from lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e+6.dat rename to lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_size10_num5_cshift0_s15.36e6.dat index 5d80549fc..bb2c793e3 100644 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e+6.dat and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_size10_num5_cshift0_s15.36e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_s1.92e+6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_s1.92e+6.dat deleted file mode 100644 index 81af16863..000000000 Binary files a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_s1.92e+6.dat and /dev/null differ diff --git a/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_size6_num1_cshift0_s1.92e6.dat b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_size6_num1_cshift0_s1.92e6.dat new file mode 100644 index 000000000..e55792f25 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_size6_num1_cshift0_s1.92e6.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat b/lib/src/phy/phch/test/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat new file mode 100755 index 000000000..b79e62cd5 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat b/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat new file mode 100755 index 000000000..2fd34cfc2 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat b/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat new file mode 100755 index 000000000..2e84ddf95 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat b/lib/src/phy/phch/test/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat new file mode 100755 index 000000000..02acd3e56 Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat differ diff --git a/lib/src/phy/phch/test/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat b/lib/src/phy/phch/test/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat new file mode 100755 index 000000000..0cc88ddfa Binary files /dev/null and b/lib/src/phy/phch/test/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat differ diff --git a/lib/src/phy/sync/cfo.c b/lib/src/phy/sync/cfo.c index 2ac643853..441adb779 100644 --- a/lib/src/phy/sync/cfo.c +++ b/lib/src/phy/sync/cfo.c @@ -146,4 +146,50 @@ float srslte_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb) 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; +} + +/* + * Sidelink CFO estimation and correction based on cp + */ +float srslte_sl_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb, srslte_cp_t cp) +{ + int symbol_sz = srslte_symbol_sz(nof_prb); + int sf_n_samples = SRSLTE_SF_LEN_PRB(nof_prb); + float tFFT = (float)(1 / 15000.0); + int cp_size = SRSLTE_CP_SZ(symbol_sz, cp); + int cp_size_0 = (cp == SRSLTE_CP_NORM) ? SRSLTE_CP_LEN_NORM(0, symbol_sz) : cp_size; + + // Compensate for initial SC-FDMA half subcarrier shift, cfo = 7500 / (15000 * symbol_sz) <=> 1 / (symbol_sz * 2.0) + srslte_vec_apply_cfo(input_buffer, (1 / (float)(symbol_sz * 2.0)), input_buffer, sf_n_samples); + + uint32_t p1 = 0; + uint32_t p2 = symbol_sz; + uint32_t cp_len = 0; + + uint32_t sf_n_symbols = (cp == SRSLTE_CP_NORM) + ? (14 - 1) + : (12 - 1); // // 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. + + cf_t average_cfo = 0.0f; + + for (int i = 0; i < sf_n_symbols; i++) { + // Calculate CP length + cp_len = (i == 0 || i == SRSLTE_CP_NSYMB(cp)) ? cp_size_0 : cp_size; + + // Correlate CP with tail + average_cfo += srslte_vec_dot_prod_conj_ccc(&input_buffer[p2], &input_buffer[p1], cp_len); + + // Increment pointers for next symbol + p1 += cp_len + symbol_sz; + p2 += cp_len + symbol_sz; + } + + float cfo = (float)(carg(average_cfo) / (float)(2 * M_PI * tFFT)); + + // Compensate for initial SC-FDMA half subcarrier shift, cfo = - 7500 / (15000 * symbol_sz) <=> 1 / (symbol_sz * 2.0) + srslte_vec_apply_cfo( + input_buffer, (-1 / (float)(symbol_sz * 2.0)) + (-cfo / (float)(15e3 * symbol_sz)), input_buffer, sf_n_samples); + + return cfo; } \ No newline at end of file