501 lines
17 KiB
C
501 lines
17 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
/**********************************************************************
|
|
*
|
|
* FILENAME : dmrs_nr.c
|
|
*
|
|
* MODULE : demodulation reference signals
|
|
*
|
|
* DESCRIPTION : generation of dmrs sequences
|
|
* 3GPP TS 38.211
|
|
*
|
|
************************************************************************/
|
|
|
|
#include "PHY/NR_REFSIG/ss_pbch_nr.h"
|
|
#include "PHY/NR_REFSIG/dmrs_nr.h"
|
|
|
|
/***********************************************************************/
|
|
|
|
// TS 38.211 Table 6.4.1.1.3-3: PUSCH DMRS positions l' within a slot for single-symbol DMRS and intra-slot frequency hopping disabled.
|
|
// The first 4 colomns are PUSCH mapping type A and the last 4 colomns are PUSCH mapping type B.
|
|
// When l' = l0, it is represented by 1
|
|
// E.g. when symbol duration is 12 in colomn 7, value 1057 ('10000100001') which means l' = l0, 5, 10.
|
|
|
|
int32_t table_6_4_1_1_3_3_pusch_dmrs_positions_l [12][8] = { // Duration in symbols
|
|
{-1, -1, -1, -1, 1, 1, 1, 1}, //<4 // (DMRS l' position)
|
|
{1, 1, 1, 1, 1, 1, 1, 1}, //4 // (DMRS l' position)
|
|
{1, 1, 1, 1, 1, 5, 5, 5}, //5 // (DMRS l' position)
|
|
{1, 1, 1, 1, 1, 5, 5, 5}, //6 // (DMRS l' position)
|
|
{1, 1, 1, 1, 1, 5, 5, 5}, //7 // (DMRS l' position)
|
|
{1, 129, 129, 129, 1, 65, 73, 73}, //8 // (DMRS l' position)
|
|
{1, 129, 129, 129, 1, 65, 73, 73}, //9 // (DMRS l' position)
|
|
{1, 513, 577, 577, 1, 257, 273, 585}, //10 // (DMRS l' position)
|
|
{1, 513, 577, 577, 1, 257, 273, 585}, //11 // (DMRS l' position)
|
|
{1, 513, 577, 2337, 1, 1025, 1057, 585}, //12 // (DMRS l' position)
|
|
{1, 2049, 2177, 2337, 1, 1025, 1057, 585}, //13 // (DMRS l' position)
|
|
{1, 2049, 2177, 2337, 1, 1025, 1057, 585}, //14 // (DMRS l' position)
|
|
};
|
|
|
|
|
|
// TS 38.211 Table 6.4.1.1.3-4: PUSCH DMRS positions l' within a slot for double-symbol DMRS and intra-slot frequency hopping disabled.
|
|
// The first 4 colomns are PUSCH mapping type A and the last 4 colomns are PUSCH mapping type B.
|
|
// When l' = l0, it is represented by 1
|
|
|
|
int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l [12][8] = { // Duration in symbols
|
|
{-1, -1, -1, -1, -1, -1, -1, -1}, //<4 // (DMRS l' position)
|
|
{1, 1, -1, -1, -1, -1, -1, -1}, //4 // (DMRS l' position)
|
|
{1, 1, -1, -1, 1, 1, -1, -1}, //5 // (DMRS l' position)
|
|
{1, 1, -1, -1, 1, 1, -1, -1}, //6 // (DMRS l' position)
|
|
{1, 1, -1, -1, 1, 1, -1, -1}, //7 // (DMRS l' position)
|
|
{1, 1, -1, -1, 1, 33, -1, -1}, //8 // (DMRS l' position)
|
|
{1, 1, -1, -1, 1, 33, -1, -1}, //9 // (DMRS l' position)
|
|
{1, 257, -1, -1, 1, 129, -1, -1}, //10 // (DMRS l' position)
|
|
{1, 257, -1, -1, 1, 129, -1, -1}, //11 // (DMRS l' position)
|
|
{1, 257, -1, -1, 1, 513, -1, -1}, //12 // (DMRS l' position)
|
|
{1, 1025, -1, -1, 1, 513, -1, -1}, //13 // (DMRS l' position)
|
|
{1, 1025, -1, -1, 1, 513, -1, -1}, //14 // (DMRS l' position)
|
|
};
|
|
|
|
int32_t get_l_prime(uint8_t duration_in_symbols, uint8_t mapping_type, pusch_dmrs_AdditionalPosition_t additional_pos, pusch_maxLength_t pusch_maxLength) {
|
|
|
|
uint8_t row, colomn;
|
|
int32_t l_prime;
|
|
|
|
colomn = additional_pos;
|
|
|
|
if (mapping_type == typeB)
|
|
colomn += 4;
|
|
|
|
if (duration_in_symbols < 4)
|
|
row = 0;
|
|
else
|
|
row = duration_in_symbols - 3;
|
|
|
|
if (pusch_maxLength == pusch_len1)
|
|
l_prime = table_6_4_1_1_3_3_pusch_dmrs_positions_l[row][colomn];
|
|
else
|
|
l_prime = table_6_4_1_1_3_4_pusch_dmrs_positions_l[row][colomn];
|
|
|
|
AssertFatal(l_prime>0,"invalid l_prime < 0\n");
|
|
|
|
return l_prime;
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* NAME : is_dmrs_symbol
|
|
*
|
|
* PARAMETERS : l ofdm symbol index within slot
|
|
* k subcarrier index
|
|
* start_sc first subcarrier index
|
|
* k_prime index alternating 0 and 1
|
|
* n index starting 0,1,...
|
|
* delta see Table 6.4.1.1.3
|
|
* duration_in_symbols number of scheduled PUSCH ofdm symbols
|
|
* start_symbol first symbol index in PUSCH allocation
|
|
* dmrs_UplinkConfig DMRS uplink configuration
|
|
* mapping_type PUSCH mapping type (A or B)
|
|
* ofdm_symbol_size IFFT size
|
|
*
|
|
* RETURN : 0 if symbol(k,l) is data, or 1 if symbol(k,l) is dmrs
|
|
*
|
|
* DESCRIPTION : 3GPP TS 38.211 6.4.1.1 Demodulation reference signal for PUSCH
|
|
*
|
|
*********************************************************************/
|
|
|
|
uint8_t is_dmrs_symbol(uint8_t l,
|
|
uint16_t k,
|
|
uint16_t start_sc,
|
|
uint8_t k_prime,
|
|
uint16_t n,
|
|
uint8_t delta,
|
|
uint8_t duration_in_symbols,
|
|
uint8_t dmrs_type,
|
|
uint16_t ofdm_symbol_size) {
|
|
|
|
uint8_t is_dmrs_freq, is_dmrs_time, l0;
|
|
int32_t l_prime_mask;
|
|
pusch_dmrs_AdditionalPosition_t additional_pos = pusch_dmrs_pos0;
|
|
pusch_maxLength_t pusch_maxLength = pusch_len1;
|
|
uint8_t mapping_type = typeB;
|
|
|
|
is_dmrs_freq = 0;
|
|
is_dmrs_time = 0;
|
|
|
|
AssertFatal(l >= 0,"Check DMRS configuration (start_symbol) !\n");
|
|
|
|
|
|
l0 = get_l0_ul(mapping_type, 2);
|
|
l_prime_mask = get_l_prime(duration_in_symbols, mapping_type, additional_pos, pusch_maxLength);
|
|
|
|
if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%ofdm_symbol_size))
|
|
is_dmrs_freq = 1;
|
|
|
|
|
|
if (l_prime_mask == 1){
|
|
|
|
if (l == l0)
|
|
is_dmrs_time = 1;
|
|
|
|
} else if ( (l==l0) || (((l_prime_mask>>l)&1) == 1 && l!=0) )
|
|
is_dmrs_time = 1;
|
|
|
|
if (pusch_maxLength == pusch_len2){
|
|
|
|
if (((l_prime_mask>>(l-1))&1) == 1 && l!=0 && l!=1)
|
|
is_dmrs_time = 1;
|
|
|
|
if (l-1 == l0)
|
|
is_dmrs_time = 1;
|
|
|
|
}
|
|
|
|
|
|
if (is_dmrs_time && is_dmrs_freq)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* NAME : pseudo_random_gold_sequence
|
|
*
|
|
* PARAMETERS :
|
|
*
|
|
* RETURN : generate pseudo-random sequence which is a length-31 Gold sequence
|
|
*
|
|
* DESCRIPTION : 3GPP TS 38.211 5.2.1 Pseudo-random sequence generation
|
|
* Sequence generation is a length-31 Gold sequence
|
|
*
|
|
*********************************************************************/
|
|
|
|
#define NC (1600)
|
|
#define GOLD_SEQUENCE_LENGTH (31)
|
|
|
|
int pseudo_random_sequence(int M_PN, uint32_t *c, uint32_t cinit)
|
|
{
|
|
int n;
|
|
int size_x = NC + GOLD_SEQUENCE_LENGTH + M_PN;
|
|
uint32_t *x1;
|
|
uint32_t *x2;
|
|
|
|
x1 = calloc(size_x, sizeof(uint32_t));
|
|
|
|
if (x1 == NULL) {
|
|
msg("Fatal error: memory allocation problem \n");
|
|
assert(0);
|
|
}
|
|
|
|
x2 = calloc(size_x, sizeof(uint32_t));
|
|
|
|
if (x2 == NULL) {
|
|
free(x1);
|
|
msg("Fatal error: memory allocation problem \n");
|
|
assert(0);
|
|
}
|
|
|
|
x1[0] = 1; /* init first m sequence */
|
|
|
|
/* cinit allows to initialise second m-sequence x2 */
|
|
for (n = 0; n < GOLD_SEQUENCE_LENGTH; n++) {
|
|
x2[n] = (cinit >> n) & 0x1;
|
|
}
|
|
|
|
for (n = 0; n < (NC + M_PN); n++) {
|
|
x1[n+31] = (x1[n+3] + x1[n])%2;
|
|
x2[n+31] = (x2[n+3] + x2[n+2] + x2[n+1] + x2[n])%2;
|
|
}
|
|
|
|
for (int n = 0; n < M_PN; n++) {
|
|
c[n] = (x1[n+NC] + x2[n+NC])%2;
|
|
}
|
|
|
|
free(x1);
|
|
free(x2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* NAME : pseudo_random_sequence_optimised
|
|
*
|
|
* PARAMETERS :
|
|
*
|
|
* RETURN : generate pseudo-random sequence which is a length-31 Gold sequence
|
|
*
|
|
* DESCRIPTION : 3GPP TS 38.211 5.2.1 Pseudo-random sequence generation
|
|
* Sequence generation is a length-31 Gold sequence
|
|
* This is an optimized function based on bitmap variables
|
|
*
|
|
* x1(0)=1,x1(1)=0,...x1(30)=0,x1(31)=1
|
|
* x2 <=> cinit, x2(31) = x2(3)+x2(2)+x2(1)+x2(0)
|
|
* x2 <=> cinit = sum_{i=0}^{30} x2(i)2^i
|
|
* c(n) = x1(n+Nc) + x2(n+Nc) mod 2
|
|
*
|
|
* equivalent to
|
|
* x1(n+31) = (x1(n+3)+x1(n))mod 2 <=> x1(n) = x1(n-28) + x1(n-31)
|
|
* x2(n+31) = (x2(n+3)+x2(n+2)+x2(n+1)+x2(n))mod 2 <=> x2(n) = x2(n-28) + x2(n-29) + x2(n-30) + x2(n-31)
|
|
*
|
|
*********************************************************************/
|
|
|
|
void pseudo_random_sequence_optimised(unsigned int size, uint32_t *c, uint32_t cinit)
|
|
{
|
|
unsigned int n,x1,x2;
|
|
|
|
/* init of m-sequences */
|
|
x1 = 1+ (1<<31);
|
|
x2 = cinit;
|
|
x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31);
|
|
|
|
/* skip first 50 double words of uint32_t (1600 bits) */
|
|
for (n=1; n<50; n++) {
|
|
x1 = (x1>>1) ^ (x1>>4);
|
|
x1 = x1 ^ (x1<<31) ^ (x1<<28);
|
|
x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4);
|
|
x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28);
|
|
}
|
|
|
|
for (n=0; n<size; n++) {
|
|
x1 = (x1>>1) ^ (x1>>4);
|
|
x1 = x1 ^ (x1<<31) ^ (x1<<28);
|
|
x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4);
|
|
x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28);
|
|
c[n] = x1^x2;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* NAME : lte_gold_new
|
|
*
|
|
* PARAMETERS :
|
|
*
|
|
* RETURN : generate pseudo-random sequence which is a length-31 Gold sequence
|
|
*
|
|
* DESCRIPTION : This function is the same as "lte_gold" function in file lte_gold.c
|
|
* It allows checking that optimization works fine.
|
|
* generated sequence is given in an array as a bit map.
|
|
*
|
|
*********************************************************************/
|
|
|
|
#define CELL_DMRS_LENGTH (224*2)
|
|
#define CHECK_GOLD_SEQUENCE
|
|
|
|
void lte_gold_new(LTE_DL_FRAME_PARMS *frame_parms, uint32_t lte_gold_table[20][2][14], uint16_t Nid_cell)
|
|
{
|
|
unsigned char ns,l,Ncp=1-frame_parms->Ncp;
|
|
uint32_t cinit;
|
|
|
|
#ifdef CHECK_GOLD_SEQUENCE
|
|
|
|
uint32_t dmrs_bitmap[20][2][14];
|
|
uint32_t *dmrs_sequence = calloc(CELL_DMRS_LENGTH, sizeof(uint32_t));
|
|
if (dmrs_sequence == NULL) {
|
|
msg("Fatal error: memory allocation problem \n");
|
|
assert(0);
|
|
}
|
|
else
|
|
{
|
|
printf("Check of demodulation reference signal of pbch sequence \n");
|
|
}
|
|
|
|
#endif
|
|
|
|
/* for each slot number */
|
|
for (ns=0; ns<20; ns++) {
|
|
|
|
/* for each ofdm position */
|
|
for (l=0; l<2; l++) {
|
|
|
|
cinit = Ncp +
|
|
(Nid_cell<<1) +
|
|
(((1+(Nid_cell<<1))*(1 + (((frame_parms->Ncp==0)?4:3)*l) + (7*(1+ns))))<<10);
|
|
|
|
pseudo_random_sequence_optimised(14, &(lte_gold_table[ns][l][0]), cinit);
|
|
|
|
#ifdef CHECK_GOLD_SEQUENCE
|
|
|
|
pseudo_random_sequence(CELL_DMRS_LENGTH, dmrs_sequence, cinit);
|
|
|
|
int j = 0;
|
|
int k = 0;
|
|
|
|
/* format for getting bitmap from uint32_t */
|
|
for (int i=0; i<14; i++) {
|
|
dmrs_bitmap[ns][l][i] = 0;
|
|
for (; j < k + 32; j++) {
|
|
dmrs_bitmap[ns][l][i] |= (dmrs_sequence[j]<<j);
|
|
}
|
|
k = j;
|
|
}
|
|
|
|
for (int i=0; i<14; i++) {
|
|
if (lte_gold_table[ns][l][i] != dmrs_bitmap[ns][l][i]) {
|
|
printf("Error in gold sequence computation for ns %d l %d and index %i : 0x%x 0x%x \n", ns, l, i, lte_gold_table[ns][l][i], dmrs_bitmap[ns][l][i]);
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef CHECK_GOLD_SEQUENCE
|
|
free(dmrs_sequence);
|
|
#endif
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* NAME : get_l0_ul
|
|
*
|
|
* PARAMETERS : mapping_type : PUSCH mapping type
|
|
* dmrs_typeA_position : higher layer parameter
|
|
*
|
|
* RETURN : demodulation reference signal for PUSCH
|
|
*
|
|
* DESCRIPTION : see TS 38.211 V15.4.0 Demodulation reference signals for PUSCH
|
|
*
|
|
*********************************************************************/
|
|
|
|
uint8_t get_l0_ul(uint8_t mapping_type, uint8_t dmrs_typeA_position) {
|
|
|
|
return ((mapping_type==typeA)?dmrs_typeA_position:0);
|
|
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* NAME : get_dmrs_freq_idx_ul
|
|
*
|
|
* PARAMETERS : n : index of DMRS symbol
|
|
* k_prime : k_prime = {0,1}
|
|
* delta : given by Tables 6.4.1.1.3-1 and 6.4.1.1.3-2
|
|
* dmrs_type : DMRS configuration type
|
|
*
|
|
* RETURN : demodulation reference signal for PUSCH
|
|
*
|
|
* DESCRIPTION : see TS 38.211 V15.4.0 Demodulation reference signals for PUSCH
|
|
*
|
|
*********************************************************************/
|
|
|
|
uint16_t get_dmrs_freq_idx_ul(uint16_t n, uint8_t k_prime, uint8_t delta, uint8_t dmrs_type) {
|
|
|
|
uint16_t dmrs_idx;
|
|
|
|
if (dmrs_type == pusch_dmrs_type1)
|
|
dmrs_idx = ((n<<2)+(k_prime<<1)+delta);
|
|
else
|
|
dmrs_idx = (6*n+k_prime+delta);
|
|
|
|
return dmrs_idx;
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* NAME : get_dmrs_pbch
|
|
*
|
|
* PARAMETERS : i_ssb : index of ssb/pbch beam
|
|
* n_hf : number of the half frame in which PBCH is transmitted in frame
|
|
*
|
|
* RETURN : demodulation reference signal for PBCH
|
|
*
|
|
* DESCRIPTION : see TS 38.211 7.4.1.4 Demodulation reference signals for PBCH
|
|
*
|
|
*********************************************************************/
|
|
|
|
#define CHECK_DMRS_PBCH_SEQUENCE
|
|
|
|
void generate_dmrs_pbch(uint32_t dmrs_pbch_bitmap[DMRS_PBCH_I_SSB][DMRS_PBCH_N_HF][DMRS_BITMAP_SIZE], uint16_t Nid_cell)
|
|
{
|
|
uint32_t cinit;
|
|
int i_ssb;
|
|
int n_hf;
|
|
int _i_ssb;
|
|
|
|
#ifdef CHECK_DMRS_PBCH_SEQUENCE
|
|
|
|
uint32_t dmrs_bitmap[DMRS_PBCH_I_SSB][DMRS_PBCH_N_HF][DMRS_BITMAP_SIZE];
|
|
uint32_t *dmrs_sequence = calloc(CELL_DMRS_LENGTH, sizeof(uint32_t));
|
|
if (dmrs_sequence == NULL) {
|
|
msg("Fatal error: memory allocation problem \n");
|
|
assert(0);
|
|
}
|
|
else
|
|
{
|
|
printf("Check of demodulation reference signal of pbch sequence \n");
|
|
}
|
|
|
|
#endif
|
|
|
|
/* for each slot number */
|
|
for (i_ssb = 0; i_ssb<DMRS_PBCH_I_SSB; i_ssb++) {
|
|
|
|
/* for each ofdm position */
|
|
for (n_hf=0; n_hf<DMRS_PBCH_N_HF; n_hf++) {
|
|
|
|
_i_ssb = i_ssb + 4*n_hf;
|
|
|
|
cinit = (((_i_ssb + 1)*((Nid_cell>>4) + 1))<<11) + ((_i_ssb + 1)<<6) + (Nid_cell%4);
|
|
|
|
pseudo_random_sequence_optimised(DMRS_BITMAP_SIZE, &(dmrs_pbch_bitmap[i_ssb][n_hf][0]), cinit);
|
|
|
|
#ifdef CHECK_DMRS_PBCH_SEQUENCE
|
|
|
|
/* it allows checking generated with standard generation code */
|
|
pseudo_random_sequence(DMRS_BITMAP_SIZE*sizeof(uint32_t), dmrs_sequence, cinit);
|
|
|
|
int j = 0;
|
|
int k = 0;
|
|
|
|
/* format for getting bitmap from uint32_t */
|
|
for (int i=0; i<DMRS_BITMAP_SIZE; i++) {
|
|
dmrs_bitmap[i_ssb][n_hf][i] = 0;
|
|
/* convert to bitmap */
|
|
for (; j < k + 32; j++) {
|
|
dmrs_bitmap[i_ssb][n_hf][i] |= (dmrs_sequence[j]<<j);
|
|
}
|
|
k = j;
|
|
}
|
|
|
|
for (int i=0; i<DMRS_BITMAP_SIZE; i++) {
|
|
if (dmrs_pbch_bitmap[i_ssb][n_hf][i] != dmrs_bitmap[i_ssb][n_hf][i]) {
|
|
printf("Error in gold sequence computation for ns %d l %d and index %i : 0x%x 0x%x \n", i_ssb, n_hf, i, dmrs_pbch_bitmap[i_ssb][n_hf][i], dmrs_bitmap[i_ssb][n_hf][i]);
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef CHECK_DMRS_PBCH_SEQUENCE
|
|
free(dmrs_sequence);
|
|
#endif
|
|
}
|
|
|