Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ZhouShuya
OpenXG-RAN
Commits
fe95f0f4
Commit
fe95f0f4
authored
Mar 19, 2018
by
Raymond Knopp
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
created new directories for NBIoT and NR and split eNB/gNB/UE
parent
d943cd28
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
7293 additions
and
0 deletions
+7293
-0
openair1/PHY/LTE_UE_TRANSPORT/dci_ue.c
openair1/PHY/LTE_UE_TRANSPORT/dci_ue.c
+3681
-0
openair1/PHY/LTE_UE_TRANSPORT/pbch_ue.c
openair1/PHY/LTE_UE_TRANSPORT/pbch_ue.c
+631
-0
openair1/PHY/LTE_UE_TRANSPORT/pcfich_ue.c
openair1/PHY/LTE_UE_TRANSPORT/pcfich_ue.c
+312
-0
openair1/PHY/LTE_UE_TRANSPORT/pch_ue.c
openair1/PHY/LTE_UE_TRANSPORT/pch_ue.c
+54
-0
openair1/PHY/LTE_UE_TRANSPORT/phich_ue.c
openair1/PHY/LTE_UE_TRANSPORT/phich_ue.c
+1570
-0
openair1/PHY/LTE_UE_TRANSPORT/pmch_ue.c
openair1/PHY/LTE_UE_TRANSPORT/pmch_ue.c
+1045
-0
No files found.
openair1/PHY/LTE_UE_TRANSPORT/dci_ue.c
0 → 100755
View file @
fe95f0f4
This source diff could not be displayed because it is too large. You can
view the blob
instead.
openair1/PHY/LTE_UE_TRANSPORT/pbch_ue.c
0 → 100644
View file @
fe95f0f4
/*
* 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
*/
/*! \file PHY/LTE_TRANSPORT/pbch.c
* \brief Top-level routines for generating and decoding the PBCH/BCH physical/transport channel V8.6 2009-03
* \author R. Knopp, F. Kaltenberger
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr,florian.kaltenberger.fr
* \note
* \warning
*/
#include "PHY/defs.h"
#include "PHY/CODING/extern.h"
#include "PHY/CODING/lte_interleaver_inline.h"
#include "defs.h"
#include "extern.h"
#include "PHY/extern.h"
#include "PHY/sse_intrin.h"
//#define DEBUG_PBCH 1
//#define DEBUG_PBCH_ENCODING
//#define INTERFERENCE_MITIGATION 1
#define PBCH_A 24
uint16_t
pbch_extract
(
int
**
rxdataF
,
int
**
dl_ch_estimates
,
int
**
rxdataF_ext
,
int
**
dl_ch_estimates_ext
,
uint32_t
symbol
,
uint32_t
high_speed_flag
,
LTE_DL_FRAME_PARMS
*
frame_parms
)
{
uint16_t
rb
,
nb_rb
=
6
;
uint8_t
i
,
j
,
aarx
,
aatx
;
int
*
dl_ch0
,
*
dl_ch0_ext
,
*
rxF
,
*
rxF_ext
;
uint32_t
nsymb
=
(
frame_parms
->
Ncp
==
0
)
?
7
:
6
;
uint32_t
symbol_mod
=
symbol
%
nsymb
;
int
rx_offset
=
frame_parms
->
ofdm_symbol_size
-
3
*
12
;
int
ch_offset
=
frame_parms
->
N_RB_DL
*
6
-
3
*
12
;
int
nushiftmod3
=
frame_parms
->
nushift
%
3
;
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
{
/*
printf("extract_rbs (nushift %d): symbol_mod=%d, rx_offset=%d, ch_offset=%d\n",frame_parms->nushift,symbol_mod,
(rx_offset + (symbol*(frame_parms->ofdm_symbol_size)))*2,
LTE_CE_OFFSET+ch_offset+(symbol_mod*(frame_parms->ofdm_symbol_size)));
*/
rxF
=
&
rxdataF
[
aarx
][(
rx_offset
+
(
symbol
*
(
frame_parms
->
ofdm_symbol_size
)))];
rxF_ext
=
&
rxdataF_ext
[
aarx
][
symbol_mod
*
(
6
*
12
)];
for
(
rb
=
0
;
rb
<
nb_rb
;
rb
++
)
{
// skip DC carrier
if
(
rb
==
3
)
{
rxF
=
&
rxdataF
[
aarx
][(
1
+
(
symbol
*
(
frame_parms
->
ofdm_symbol_size
)))];
}
if
((
symbol_mod
==
0
)
||
(
symbol_mod
==
1
))
{
j
=
0
;
for
(
i
=
0
;
i
<
12
;
i
++
)
{
if
((
i
!=
nushiftmod3
)
&&
(
i
!=
(
nushiftmod3
+
3
))
&&
(
i
!=
(
nushiftmod3
+
6
))
&&
(
i
!=
(
nushiftmod3
+
9
)))
{
rxF_ext
[
j
++
]
=
rxF
[
i
];
}
}
rxF
+=
12
;
rxF_ext
+=
8
;
}
else
{
for
(
i
=
0
;
i
<
12
;
i
++
)
{
rxF_ext
[
i
]
=
rxF
[
i
];
}
rxF
+=
12
;
rxF_ext
+=
12
;
}
}
for
(
aatx
=
0
;
aatx
<
4
;
aatx
++
)
{
//frame_parms->nb_antenna_ports_eNB;aatx++) {
if
(
high_speed_flag
==
1
)
dl_ch0
=
&
dl_ch_estimates
[(
aatx
<<
1
)
+
aarx
][
LTE_CE_OFFSET
+
ch_offset
+
(
symbol
*
(
frame_parms
->
ofdm_symbol_size
))];
else
dl_ch0
=
&
dl_ch_estimates
[(
aatx
<<
1
)
+
aarx
][
LTE_CE_OFFSET
+
ch_offset
];
dl_ch0_ext
=
&
dl_ch_estimates_ext
[(
aatx
<<
1
)
+
aarx
][
symbol_mod
*
(
6
*
12
)];
for
(
rb
=
0
;
rb
<
nb_rb
;
rb
++
)
{
// skip DC carrier
// if (rb==3) dl_ch0++;
if
(
symbol_mod
>
1
)
{
memcpy
(
dl_ch0_ext
,
dl_ch0
,
12
*
sizeof
(
int
));
dl_ch0
+=
12
;
dl_ch0_ext
+=
12
;
}
else
{
j
=
0
;
for
(
i
=
0
;
i
<
12
;
i
++
)
{
if
((
i
!=
nushiftmod3
)
&&
(
i
!=
(
nushiftmod3
+
3
))
&&
(
i
!=
(
nushiftmod3
+
6
))
&&
(
i
!=
(
nushiftmod3
+
9
)))
{
// printf("PBCH extract i %d j %d => (%d,%d)\n",i,j,*(short *)&dl_ch0[i],*(1+(short*)&dl_ch0[i]));
dl_ch0_ext
[
j
++
]
=
dl_ch0
[
i
];
}
}
dl_ch0
+=
12
;
dl_ch0_ext
+=
8
;
}
}
}
//tx antenna loop
}
return
(
0
);
}
//__m128i avg128;
//compute average channel_level on each (TX,RX) antenna pair
int
pbch_channel_level
(
int
**
dl_ch_estimates_ext
,
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint32_t
symbol
)
{
int16_t
rb
,
nb_rb
=
6
;
uint8_t
aatx
,
aarx
;
#if defined(__x86_64__) || defined(__i386__)
__m128i
avg128
;
__m128i
*
dl_ch128
;
#elif defined(__arm__)
int32x4_t
avg128
;
int16x8_t
*
dl_ch128
;
#endif
int
avg1
=
0
,
avg2
=
0
;
uint32_t
nsymb
=
(
frame_parms
->
Ncp
==
0
)
?
7
:
6
;
uint32_t
symbol_mod
=
symbol
%
nsymb
;
for
(
aatx
=
0
;
aatx
<
4
;
aatx
++
)
//frame_parms->nb_antenna_ports_eNB;aatx++)
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
{
//clear average level
#if defined(__x86_64__) || defined(__i386__)
avg128
=
_mm_setzero_si128
();
dl_ch128
=
(
__m128i
*
)
&
dl_ch_estimates_ext
[(
aatx
<<
1
)
+
aarx
][
symbol_mod
*
6
*
12
];
#elif defined(__arm__)
avg128
=
vdupq_n_s32
(
0
);
dl_ch128
=
(
int16x8_t
*
)
&
dl_ch_estimates_ext
[(
aatx
<<
1
)
+
aarx
][
symbol_mod
*
6
*
12
];
#endif
for
(
rb
=
0
;
rb
<
nb_rb
;
rb
++
)
{
#if defined(__x86_64__) || defined(__i386__)
avg128
=
_mm_add_epi32
(
avg128
,
_mm_madd_epi16
(
dl_ch128
[
0
],
dl_ch128
[
0
]));
avg128
=
_mm_add_epi32
(
avg128
,
_mm_madd_epi16
(
dl_ch128
[
1
],
dl_ch128
[
1
]));
avg128
=
_mm_add_epi32
(
avg128
,
_mm_madd_epi16
(
dl_ch128
[
2
],
dl_ch128
[
2
]));
#elif defined(__arm__)
// to be filled in
#endif
dl_ch128
+=
3
;
/*
if (rb==0) {
print_shorts("dl_ch128",&dl_ch128[0]);
print_shorts("dl_ch128",&dl_ch128[1]);
print_shorts("dl_ch128",&dl_ch128[2]);
}
*/
}
avg1
=
(((
int
*
)
&
avg128
)[
0
]
+
((
int
*
)
&
avg128
)[
1
]
+
((
int
*
)
&
avg128
)[
2
]
+
((
int
*
)
&
avg128
)[
3
])
/
(
nb_rb
*
12
);
if
(
avg1
>
avg2
)
avg2
=
avg1
;
//msg("Channel level : %d, %d\n",avg1, avg2);
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
return
(
avg2
);
}
#if defined(__x86_64__) || defined(__i386__)
__m128i
mmtmpP0
,
mmtmpP1
,
mmtmpP2
,
mmtmpP3
;
#elif defined(__arm__)
int16x8_t
mmtmpP0
,
mmtmpP1
,
mmtmpP2
,
mmtmpP3
;
#endif
void
pbch_channel_compensation
(
int
**
rxdataF_ext
,
int
**
dl_ch_estimates_ext
,
int
**
rxdataF_comp
,
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
symbol
,
uint8_t
output_shift
)
{
uint16_t
rb
,
nb_rb
=
6
;
uint8_t
aatx
,
aarx
,
symbol_mod
;
#if defined(__x86_64__) || defined(__i386__)
__m128i
*
dl_ch128
,
*
rxdataF128
,
*
rxdataF_comp128
;
#elif defined(__arm__)
#endif
symbol_mod
=
(
symbol
>=
(
7
-
frame_parms
->
Ncp
))
?
symbol
-
(
7
-
frame_parms
->
Ncp
)
:
symbol
;
for
(
aatx
=
0
;
aatx
<
4
;
aatx
++
)
//frame_parms->nb_antenna_ports_eNB;aatx++)
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
{
#if defined(__x86_64__) || defined(__i386__)
dl_ch128
=
(
__m128i
*
)
&
dl_ch_estimates_ext
[(
aatx
<<
1
)
+
aarx
][
symbol_mod
*
6
*
12
];
rxdataF128
=
(
__m128i
*
)
&
rxdataF_ext
[
aarx
][
symbol_mod
*
6
*
12
];
rxdataF_comp128
=
(
__m128i
*
)
&
rxdataF_comp
[(
aatx
<<
1
)
+
aarx
][
symbol_mod
*
6
*
12
];
#elif defined(__arm__)
// to be filled in
#endif
for
(
rb
=
0
;
rb
<
nb_rb
;
rb
++
)
{
//printf("rb %d\n",rb);
#if defined(__x86_64__) || defined(__i386__)
// multiply by conjugated channel
mmtmpP0
=
_mm_madd_epi16
(
dl_ch128
[
0
],
rxdataF128
[
0
]);
// print_ints("re",&mmtmpP0);
// mmtmpP0 contains real part of 4 consecutive outputs (32-bit)
mmtmpP1
=
_mm_shufflelo_epi16
(
dl_ch128
[
0
],
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpP1
=
_mm_shufflehi_epi16
(
mmtmpP1
,
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpP1
=
_mm_sign_epi16
(
mmtmpP1
,
*
(
__m128i
*
)
&
conjugate
[
0
]);
// print_ints("im",&mmtmpP1);
mmtmpP1
=
_mm_madd_epi16
(
mmtmpP1
,
rxdataF128
[
0
]);
// mmtmpP1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpP0
=
_mm_srai_epi32
(
mmtmpP0
,
output_shift
);
// print_ints("re(shift)",&mmtmpP0);
mmtmpP1
=
_mm_srai_epi32
(
mmtmpP1
,
output_shift
);
// print_ints("im(shift)",&mmtmpP1);
mmtmpP2
=
_mm_unpacklo_epi32
(
mmtmpP0
,
mmtmpP1
);
mmtmpP3
=
_mm_unpackhi_epi32
(
mmtmpP0
,
mmtmpP1
);
// print_ints("c0",&mmtmpP2);
// print_ints("c1",&mmtmpP3);
rxdataF_comp128
[
0
]
=
_mm_packs_epi32
(
mmtmpP2
,
mmtmpP3
);
// print_shorts("rx:",rxdataF128);
// print_shorts("ch:",dl_ch128);
// print_shorts("pack:",rxdataF_comp128);
// multiply by conjugated channel
mmtmpP0
=
_mm_madd_epi16
(
dl_ch128
[
1
],
rxdataF128
[
1
]);
// mmtmpP0 contains real part of 4 consecutive outputs (32-bit)
mmtmpP1
=
_mm_shufflelo_epi16
(
dl_ch128
[
1
],
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpP1
=
_mm_shufflehi_epi16
(
mmtmpP1
,
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpP1
=
_mm_sign_epi16
(
mmtmpP1
,
*
(
__m128i
*
)
&
conjugate
[
0
]);
mmtmpP1
=
_mm_madd_epi16
(
mmtmpP1
,
rxdataF128
[
1
]);
// mmtmpP1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpP0
=
_mm_srai_epi32
(
mmtmpP0
,
output_shift
);
mmtmpP1
=
_mm_srai_epi32
(
mmtmpP1
,
output_shift
);
mmtmpP2
=
_mm_unpacklo_epi32
(
mmtmpP0
,
mmtmpP1
);
mmtmpP3
=
_mm_unpackhi_epi32
(
mmtmpP0
,
mmtmpP1
);
rxdataF_comp128
[
1
]
=
_mm_packs_epi32
(
mmtmpP2
,
mmtmpP3
);
// print_shorts("rx:",rxdataF128+1);
// print_shorts("ch:",dl_ch128+1);
// print_shorts("pack:",rxdataF_comp128+1);
if
(
symbol_mod
>
1
)
{
// multiply by conjugated channel
mmtmpP0
=
_mm_madd_epi16
(
dl_ch128
[
2
],
rxdataF128
[
2
]);
// mmtmpP0 contains real part of 4 consecutive outputs (32-bit)
mmtmpP1
=
_mm_shufflelo_epi16
(
dl_ch128
[
2
],
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpP1
=
_mm_shufflehi_epi16
(
mmtmpP1
,
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpP1
=
_mm_sign_epi16
(
mmtmpP1
,
*
(
__m128i
*
)
&
conjugate
[
0
]);
mmtmpP1
=
_mm_madd_epi16
(
mmtmpP1
,
rxdataF128
[
2
]);
// mmtmpP1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpP0
=
_mm_srai_epi32
(
mmtmpP0
,
output_shift
);
mmtmpP1
=
_mm_srai_epi32
(
mmtmpP1
,
output_shift
);
mmtmpP2
=
_mm_unpacklo_epi32
(
mmtmpP0
,
mmtmpP1
);
mmtmpP3
=
_mm_unpackhi_epi32
(
mmtmpP0
,
mmtmpP1
);
rxdataF_comp128
[
2
]
=
_mm_packs_epi32
(
mmtmpP2
,
mmtmpP3
);
// print_shorts("rx:",rxdataF128+2);
// print_shorts("ch:",dl_ch128+2);
// print_shorts("pack:",rxdataF_comp128+2);
dl_ch128
+=
3
;
rxdataF128
+=
3
;
rxdataF_comp128
+=
3
;
}
else
{
dl_ch128
+=
2
;
rxdataF128
+=
2
;
rxdataF_comp128
+=
2
;
}
#elif defined(__arm__)
// to be filled in
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
}
void
pbch_detection_mrc
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
**
rxdataF_comp
,
uint8_t
symbol
)
{
uint8_t
aatx
,
symbol_mod
;
int
i
,
nb_rb
=
6
;
#if defined(__x86_64__) || defined(__i386__)
__m128i
*
rxdataF_comp128_0
,
*
rxdataF_comp128_1
;
#elif defined(__arm__)
int16x8_t
*
rxdataF_comp128_0
,
*
rxdataF_comp128_1
;
#endif
symbol_mod
=
(
symbol
>=
(
7
-
frame_parms
->
Ncp
))
?
symbol
-
(
7
-
frame_parms
->
Ncp
)
:
symbol
;
if
(
frame_parms
->
nb_antennas_rx
>
1
)
{
for
(
aatx
=
0
;
aatx
<
4
;
aatx
++
)
{
//frame_parms->nb_antenna_ports_eNB;aatx++) {
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0
=
(
__m128i
*
)
&
rxdataF_comp
[(
aatx
<<
1
)][
symbol_mod
*
6
*
12
];
rxdataF_comp128_1
=
(
__m128i
*
)
&
rxdataF_comp
[(
aatx
<<
1
)
+
1
][
symbol_mod
*
6
*
12
];
#elif defined(__arm__)
rxdataF_comp128_0
=
(
int16x8_t
*
)
&
rxdataF_comp
[(
aatx
<<
1
)][
symbol_mod
*
6
*
12
];
rxdataF_comp128_1
=
(
int16x8_t
*
)
&
rxdataF_comp
[(
aatx
<<
1
)
+
1
][
symbol_mod
*
6
*
12
];
#endif
// MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
for
(
i
=
0
;
i
<
nb_rb
*
3
;
i
++
)
{
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0
[
i
]
=
_mm_adds_epi16
(
_mm_srai_epi16
(
rxdataF_comp128_0
[
i
],
1
),
_mm_srai_epi16
(
rxdataF_comp128_1
[
i
],
1
));
#elif defined(__arm__)
rxdataF_comp128_0
[
i
]
=
vhaddq_s16
(
rxdataF_comp128_0
[
i
],
rxdataF_comp128_1
[
i
]);
#endif
}
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
}
void
pbch_unscrambling
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int8_t
*
llr
,
uint32_t
length
,
uint8_t
frame_mod4
)
{
int
i
;
uint8_t
reset
;
uint32_t
x1
,
x2
,
s
=
0
;
reset
=
1
;
// x1 is set in first call to lte_gold_generic
x2
=
frame_parms
->
Nid_cell
;
//this is c_init in 36.211 Sec 6.6.1
// msg("pbch_unscrambling: Nid_cell = %d\n",x2);
for
(
i
=
0
;
i
<
length
;
i
++
)
{
if
(
i
%
32
==
0
)
{
s
=
lte_gold_generic
(
&
x1
,
&
x2
,
reset
);
// printf("lte_gold[%d]=%x\n",i,s);
reset
=
0
;
}
// take the quarter of the PBCH that corresponds to this frame
if
((
i
>=
(
frame_mod4
*
(
length
>>
2
)))
&&
(
i
<
((
1
+
frame_mod4
)
*
(
length
>>
2
))))
{
if
(((
s
>>
(
i
%
32
))
&
1
)
==
0
)
llr
[
i
]
=
-
llr
[
i
];
}
}
}
void
pbch_alamouti
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
**
rxdataF_comp
,
uint8_t
symbol
)
{
int16_t
*
rxF0
,
*
rxF1
;
// __m128i *ch_mag0,*ch_mag1,*ch_mag0b,*ch_mag1b;
uint8_t
rb
,
re
,
symbol_mod
;
int
jj
;
// printf("Doing alamouti\n");
symbol_mod
=
(
symbol
>=
(
7
-
frame_parms
->
Ncp
))
?
symbol
-
(
7
-
frame_parms
->
Ncp
)
:
symbol
;
jj
=
(
symbol_mod
*
6
*
12
);
rxF0
=
(
int16_t
*
)
&
rxdataF_comp
[
0
][
jj
];
//tx antenna 0 h0*y
rxF1
=
(
int16_t
*
)
&
rxdataF_comp
[
2
][
jj
];
//tx antenna 1 h1*y
for
(
rb
=
0
;
rb
<
6
;
rb
++
)
{
for
(
re
=
0
;
re
<
12
;
re
+=
2
)
{
// Alamouti RX combining
rxF0
[
0
]
=
rxF0
[
0
]
+
rxF1
[
2
];
rxF0
[
1
]
=
rxF0
[
1
]
-
rxF1
[
3
];
rxF0
[
2
]
=
rxF0
[
2
]
-
rxF1
[
0
];
rxF0
[
3
]
=
rxF0
[
3
]
+
rxF1
[
1
];
rxF0
+=
4
;
rxF1
+=
4
;
}
}
}
void
pbch_quantize
(
int8_t
*
pbch_llr8
,
int16_t
*
pbch_llr
,
uint16_t
len
)
{
uint16_t
i
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
pbch_llr
[
i
]
>
7
)
pbch_llr8
[
i
]
=
7
;
else
if
(
pbch_llr
[
i
]
<-
8
)
pbch_llr8
[
i
]
=-
8
;
else
pbch_llr8
[
i
]
=
(
char
)(
pbch_llr
[
i
]);
}
}
static
unsigned
char
dummy_w_rx
[
3
*
3
*
(
16
+
PBCH_A
)];
static
int8_t
pbch_w_rx
[
3
*
3
*
(
16
+
PBCH_A
)],
pbch_d_rx
[
96
+
(
3
*
(
16
+
PBCH_A
))];
uint16_t
rx_pbch
(
LTE_UE_COMMON
*
lte_ue_common_vars
,
LTE_UE_PBCH
*
lte_ue_pbch_vars
,
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
eNB_id
,
MIMO_mode_t
mimo_mode
,
uint32_t
high_speed_flag
,
uint8_t
frame_mod4
)
{
uint8_t
log2_maxh
;
//,aatx,aarx;
int
max_h
=
0
;
int
symbol
,
i
;
uint32_t
nsymb
=
(
frame_parms
->
Ncp
==
0
)
?
14
:
12
;
uint16_t
pbch_E
;
uint8_t
pbch_a
[
8
];
uint8_t
RCC
;
int8_t
*
pbch_e_rx
;
uint8_t
*
decoded_output
=
lte_ue_pbch_vars
->
decoded_output
;
uint16_t
crc
;
// pbch_D = 16+PBCH_A;
pbch_E
=
(
frame_parms
->
Ncp
==
0
)
?
1920
:
1728
;
//RE/RB * #RB * bits/RB (QPSK)
pbch_e_rx
=
&
lte_ue_pbch_vars
->
llr
[
frame_mod4
*
(
pbch_E
>>
2
)];
#ifdef DEBUG_PBCH
LOG_D
(
PHY
,
"[PBCH] starting symbol loop (Ncp %d, frame_mod4 %d,mimo_mode %d
\n
"
,
frame_parms
->
Ncp
,
frame_mod4
,
mimo_mode
);
#endif
// clear LLR buffer
memset
(
lte_ue_pbch_vars
->
llr
,
0
,
pbch_E
);
for
(
symbol
=
(
nsymb
>>
1
);
symbol
<
(
nsymb
>>
1
)
+
4
;
symbol
++
)
{
#ifdef DEBUG_PBCH
LOG_D
(
PHY
,
"[PBCH] starting extract
\n
"
);
#endif
pbch_extract
(
lte_ue_common_vars
->
common_vars_rx_data_per_thread
[
0
].
rxdataF
,
lte_ue_common_vars
->
common_vars_rx_data_per_thread
[
0
].
dl_ch_estimates
[
eNB_id
],
lte_ue_pbch_vars
->
rxdataF_ext
,
lte_ue_pbch_vars
->
dl_ch_estimates_ext
,
symbol
,
high_speed_flag
,
frame_parms
);
#ifdef DEBUG_PBCH
LOG_D
(
PHY
,
"[PHY] PBCH Symbol %d
\n
"
,
symbol
);
LOG_D
(
PHY
,
"[PHY] PBCH starting channel_level
\n
"
);
#endif
max_h
=
pbch_channel_level
(
lte_ue_pbch_vars
->
dl_ch_estimates_ext
,
frame_parms
,
symbol
);
log2_maxh
=
3
+
(
log2_approx
(
max_h
)
/
2
);
#ifdef DEBUG_PBCH
LOG_D
(
PHY
,
"[PHY] PBCH log2_maxh = %d (%d)
\n
"
,
log2_maxh
,
max_h
);
#endif
pbch_channel_compensation
(
lte_ue_pbch_vars
->
rxdataF_ext
,
lte_ue_pbch_vars
->
dl_ch_estimates_ext
,
lte_ue_pbch_vars
->
rxdataF_comp
,
frame_parms
,
symbol
,
log2_maxh
);
// log2_maxh+I0_shift
if
(
frame_parms
->
nb_antennas_rx
>
1
)
pbch_detection_mrc
(
frame_parms
,
lte_ue_pbch_vars
->
rxdataF_comp
,
symbol
);
if
(
mimo_mode
==
ALAMOUTI
)
{
pbch_alamouti
(
frame_parms
,
lte_ue_pbch_vars
->
rxdataF_comp
,
symbol
);
}
else
if
(
mimo_mode
!=
SISO
)
{
LOG_D
(
PHY
,
"[PBCH][RX] Unsupported MIMO mode
\n
"
);
return
(
-
1
);
}
if
(
symbol
>
(
nsymb
>>
1
)
+
1
)
{
pbch_quantize
(
pbch_e_rx
,
(
short
*
)
&
(
lte_ue_pbch_vars
->
rxdataF_comp
[
0
][(
symbol
%
(
nsymb
>>
1
))
*
72
]),
144
);
pbch_e_rx
+=
144
;
}
else
{
pbch_quantize
(
pbch_e_rx
,
(
short
*
)
&
(
lte_ue_pbch_vars
->
rxdataF_comp
[
0
][(
symbol
%
(
nsymb
>>
1
))
*
72
]),
96
);
pbch_e_rx
+=
96
;
}
}
pbch_e_rx
=
lte_ue_pbch_vars
->
llr
;
//un-scrambling
#ifdef DEBUG_PBCH
LOG_D
(
PHY
,
"[PBCH] doing unscrambling
\n
"
);
#endif
pbch_unscrambling
(
frame_parms
,
pbch_e_rx
,
pbch_E
,
frame_mod4
);
//un-rate matching
#ifdef DEBUG_PBCH
LOG_D
(
PHY
,
"[PBCH] doing un-rate-matching
\n
"
);
#endif
memset
(
dummy_w_rx
,
0
,
3
*
3
*
(
16
+
PBCH_A
));
RCC
=
generate_dummy_w_cc
(
16
+
PBCH_A
,
dummy_w_rx
);
lte_rate_matching_cc_rx
(
RCC
,
pbch_E
,
pbch_w_rx
,
dummy_w_rx
,
pbch_e_rx
);
sub_block_deinterleaving_cc
((
unsigned
int
)(
PBCH_A
+
16
),
&
pbch_d_rx
[
96
],
&
pbch_w_rx
[
0
]);
memset
(
pbch_a
,
0
,((
16
+
PBCH_A
)
>>
3
));
phy_viterbi_lte_sse2
(
pbch_d_rx
+
96
,
pbch_a
,
16
+
PBCH_A
);
// Fix byte endian of PBCH (bit 23 goes in first)
for
(
i
=
0
;
i
<
(
PBCH_A
>>
3
);
i
++
)
decoded_output
[(
PBCH_A
>>
3
)
-
i
-
1
]
=
pbch_a
[
i
];
#ifdef DEBUG_PBCH
for
(
i
=
0
;
i
<
(
PBCH_A
>>
3
);
i
++
)
LOG_I
(
PHY
,
"[PBCH] pbch_a[%d] = %x
\n
"
,
i
,
decoded_output
[
i
]);
#endif //DEBUG_PBCH
#ifdef DEBUG_PBCH
LOG_I
(
PHY
,
"PBCH CRC %x : %x
\n
"
,
crc16
(
pbch_a
,
PBCH_A
),
((
uint16_t
)
pbch_a
[
PBCH_A
>>
3
]
<<
8
)
+
pbch_a
[(
PBCH_A
>>
3
)
+
1
]);
#endif
crc
=
(
crc16
(
pbch_a
,
PBCH_A
)
>>
16
)
^
(((
uint16_t
)
pbch_a
[
PBCH_A
>>
3
]
<<
8
)
+
pbch_a
[(
PBCH_A
>>
3
)
+
1
]);
if
(
crc
==
0x0000
)
return
(
1
);
else
if
(
crc
==
0xffff
)
return
(
2
);
else
if
(
crc
==
0x5555
)
return
(
4
);
else
return
(
-
1
);
}
openair1/PHY/LTE_UE_TRANSPORT/pcfich_ue.c
0 → 100644
View file @
fe95f0f4
/*
* 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
*/
/*! \file PHY/LTE_TRANSPORT/pcfich.c
* \brief Top-level routines for generating and decoding the PCFICH/CFI physical/transport channel V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#include "PHY/defs.h"
//#define DEBUG_PCFICH
void
generate_pcfich_reg_mapping
(
LTE_DL_FRAME_PARMS
*
frame_parms
)
{
uint16_t
kbar
=
6
*
(
frame_parms
->
Nid_cell
%
(
2
*
frame_parms
->
N_RB_DL
));
uint16_t
first_reg
;
uint16_t
*
pcfich_reg
=
frame_parms
->
pcfich_reg
;
pcfich_reg
[
0
]
=
kbar
/
6
;
first_reg
=
pcfich_reg
[
0
];
frame_parms
->
pcfich_first_reg_idx
=
0
;
pcfich_reg
[
1
]
=
((
kbar
+
(
frame_parms
->
N_RB_DL
>>
1
)
*
6
)
%
(
frame_parms
->
N_RB_DL
*
12
))
/
6
;
if
(
pcfich_reg
[
1
]
<
pcfich_reg
[
0
])
{
frame_parms
->
pcfich_first_reg_idx
=
1
;
first_reg
=
pcfich_reg
[
1
];
}
pcfich_reg
[
2
]
=
((
kbar
+
(
frame_parms
->
N_RB_DL
)
*
6
)
%
(
frame_parms
->
N_RB_DL
*
12
))
/
6
;
if
(
pcfich_reg
[
2
]
<
first_reg
)
{
frame_parms
->
pcfich_first_reg_idx
=
2
;
first_reg
=
pcfich_reg
[
2
];
}
pcfich_reg
[
3
]
=
((
kbar
+
((
3
*
frame_parms
->
N_RB_DL
)
>>
1
)
*
6
)
%
(
frame_parms
->
N_RB_DL
*
12
))
/
6
;
if
(
pcfich_reg
[
3
]
<
first_reg
)
{
frame_parms
->
pcfich_first_reg_idx
=
3
;
first_reg
=
pcfich_reg
[
3
];
}
//#ifdef DEBUG_PCFICH
printf
(
"pcfich_reg : %d,%d,%d,%d
\n
"
,
pcfich_reg
[
0
],
pcfich_reg
[
1
],
pcfich_reg
[
2
],
pcfich_reg
[
3
]);
//#endif
}
void
pcfich_scrambling
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
subframe
,
uint8_t
*
b
,
uint8_t
*
bt
)
{
uint32_t
i
;
uint8_t
reset
;
uint32_t
x1
,
x2
,
s
=
0
;
reset
=
1
;
// x1 is set in lte_gold_generic
x2
=
((((
2
*
frame_parms
->
Nid_cell
)
+
1
)
*
(
1
+
subframe
))
<<
9
)
+
frame_parms
->
Nid_cell
;
//this is c_init in 36.211 Sec 6.7.1
for
(
i
=
0
;
i
<
32
;
i
++
)
{
if
((
i
&
0x1f
)
==
0
)
{
s
=
lte_gold_generic
(
&
x1
,
&
x2
,
reset
);
//printf("lte_gold[%d]=%x\n",i,s);
reset
=
0
;
}
bt
[
i
]
=
(
b
[
i
]
&
1
)
^
((
s
>>
(
i
&
0x1f
))
&
1
);
}
}
void
pcfich_unscrambling
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
subframe
,
int16_t
*
d
)
{
uint32_t
i
;
uint8_t
reset
;
uint32_t
x1
,
x2
,
s
=
0
;
reset
=
1
;
// x1 is set in lte_gold_generic
x2
=
((((
2
*
frame_parms
->
Nid_cell
)
+
1
)
*
(
1
+
subframe
))
<<
9
)
+
frame_parms
->
Nid_cell
;
//this is c_init in 36.211 Sec 6.7.1
for
(
i
=
0
;
i
<
32
;
i
++
)
{
if
((
i
&
0x1f
)
==
0
)
{
s
=
lte_gold_generic
(
&
x1
,
&
x2
,
reset
);
//printf("lte_gold[%d]=%x\n",i,s);
reset
=
0
;
}
if
(((
s
>>
(
i
&
0x1f
))
&
1
)
==
1
)
d
[
i
]
=-
d
[
i
];
}
}
uint8_t
pcfich_b
[
4
][
32
]
=
{{
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
},
{
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
},
{
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
,
0
,
1
,
1
},
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
}
};
void
generate_pcfich
(
uint8_t
num_pdcch_symbols
,
int16_t
amp
,
LTE_DL_FRAME_PARMS
*
frame_parms
,
int32_t
**
txdataF
,
uint8_t
subframe
)
{
uint8_t
pcfich_bt
[
32
],
nsymb
,
pcfich_quad
;
int32_t
pcfich_d
[
2
][
16
];
uint8_t
i
;
uint32_t
symbol_offset
,
m
,
re_offset
,
reg_offset
;
int16_t
gain_lin_QPSK
;
uint16_t
*
pcfich_reg
=
frame_parms
->
pcfich_reg
;
int
nushiftmod3
=
frame_parms
->
nushift
%
3
;
#ifdef DEBUG_PCFICH
LOG_D
(
PHY
,
"Generating PCFICH in subfrmae %d for %d PDCCH symbols, AMP %d, p %d, Ncp %d
\n
"
,
subframe
,
num_pdcch_symbols
,
amp
,
frame_parms
->
nb_antenna_ports_eNB
,
frame_parms
->
Ncp
);
#endif
// scrambling
if
((
num_pdcch_symbols
>
0
)
&&
(
num_pdcch_symbols
<
4
))
pcfich_scrambling
(
frame_parms
,
subframe
,
pcfich_b
[
num_pdcch_symbols
-
1
],
pcfich_bt
);
// modulation
if
(
frame_parms
->
nb_antenna_ports_eNB
==
1
)
gain_lin_QPSK
=
(
int16_t
)((
amp
*
ONE_OVER_SQRT2_Q15
)
>>
15
);
else
gain_lin_QPSK
=
amp
/
2
;
if
(
frame_parms
->
nb_antenna_ports_eNB
==
1
)
{
// SISO
for
(
i
=
0
;
i
<
16
;
i
++
)
{
((
int16_t
*
)(
&
(
pcfich_d
[
0
][
i
])))[
0
]
=
((
pcfich_bt
[
2
*
i
]
==
1
)
?
-
gain_lin_QPSK
:
gain_lin_QPSK
);
((
int16_t
*
)(
&
(
pcfich_d
[
1
][
i
])))[
0
]
=
((
pcfich_bt
[
2
*
i
]
==
1
)
?
-
gain_lin_QPSK
:
gain_lin_QPSK
);
((
int16_t
*
)(
&
(
pcfich_d
[
0
][
i
])))[
1
]
=
((
pcfich_bt
[
2
*
i
+
1
]
==
1
)
?
-
gain_lin_QPSK
:
gain_lin_QPSK
);
((
int16_t
*
)(
&
(
pcfich_d
[
1
][
i
])))[
1
]
=
((
pcfich_bt
[
2
*
i
+
1
]
==
1
)
?
-
gain_lin_QPSK
:
gain_lin_QPSK
);
}
}
else
{
// ALAMOUTI
for
(
i
=
0
;
i
<
16
;
i
+=
2
)
{
// first antenna position n -> x0
((
int16_t
*
)(
&
(
pcfich_d
[
0
][
i
])))[
0
]
=
((
pcfich_bt
[
2
*
i
]
==
1
)
?
-
gain_lin_QPSK
:
gain_lin_QPSK
);
((
int16_t
*
)(
&
(
pcfich_d
[
0
][
i
])))[
1
]
=
((
pcfich_bt
[
2
*
i
+
1
]
==
1
)
?
-
gain_lin_QPSK
:
gain_lin_QPSK
);
// second antenna position n -> -x1*
((
int16_t
*
)(
&
(
pcfich_d
[
1
][
i
])))[
0
]
=
((
pcfich_bt
[
2
*
i
+
2
]
==
1
)
?
gain_lin_QPSK
:
-
gain_lin_QPSK
);
((
int16_t
*
)(
&
(
pcfich_d
[
1
][
i
])))[
1
]
=
((
pcfich_bt
[
2
*
i
+
3
]
==
1
)
?
-
gain_lin_QPSK
:
gain_lin_QPSK
);
// fill in the rest of the ALAMOUTI precoding
((
int16_t
*
)
&
pcfich_d
[
0
][
i
+
1
])[
0
]
=
-
((
int16_t
*
)
&
pcfich_d
[
1
][
i
])[
0
];
((
int16_t
*
)
&
pcfich_d
[
0
][
i
+
1
])[
1
]
=
((
int16_t
*
)
&
pcfich_d
[
1
][
i
])[
1
];
((
int16_t
*
)
&
pcfich_d
[
1
][
i
+
1
])[
0
]
=
((
int16_t
*
)
&
pcfich_d
[
0
][
i
])[
0
];
((
int16_t
*
)
&
pcfich_d
[
1
][
i
+
1
])[
1
]
=
-
((
int16_t
*
)
&
pcfich_d
[
0
][
i
])[
1
];
}
}
// mapping
nsymb
=
(
frame_parms
->
Ncp
==
0
)
?
14
:
12
;
symbol_offset
=
(
uint32_t
)
frame_parms
->
ofdm_symbol_size
*
(
subframe
*
nsymb
);
re_offset
=
frame_parms
->
first_carrier_offset
;
// loop over 4 quadruplets and lookup REGs
m
=
0
;
for
(
pcfich_quad
=
0
;
pcfich_quad
<
4
;
pcfich_quad
++
)
{
reg_offset
=
re_offset
+
((
uint16_t
)
pcfich_reg
[
pcfich_quad
]
*
6
);
if
(
reg_offset
>=
frame_parms
->
ofdm_symbol_size
)
reg_offset
=
1
+
reg_offset
-
frame_parms
->
ofdm_symbol_size
;
for
(
i
=
0
;
i
<
6
;
i
++
)
{
if
((
i
!=
nushiftmod3
)
&&
(
i
!=
(
nushiftmod3
+
3
)))
{
txdataF
[
0
][
symbol_offset
+
reg_offset
+
i
]
=
pcfich_d
[
0
][
m
];
if
(
frame_parms
->
nb_antenna_ports_eNB
>
1
)
txdataF
[
1
][
symbol_offset
+
reg_offset
+
i
]
=
pcfich_d
[
1
][
m
];
m
++
;
}
}
}
}
uint8_t
rx_pcfich
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
subframe
,
LTE_UE_PDCCH
*
lte_ue_pdcch_vars
,
MIMO_mode_t
mimo_mode
)
{
uint8_t
pcfich_quad
;
uint8_t
i
,
j
;
uint16_t
reg_offset
;
int32_t
**
rxdataF_comp
=
lte_ue_pdcch_vars
->
rxdataF_comp
;
int16_t
pcfich_d
[
32
],
*
pcfich_d_ptr
;
int32_t
metric
,
old_metric
=-
16384
;
uint8_t
num_pdcch_symbols
=
3
;
uint16_t
*
pcfich_reg
=
frame_parms
->
pcfich_reg
;
// demapping
// loop over 4 quadruplets and lookup REGs
// m=0;
pcfich_d_ptr
=
pcfich_d
;
for
(
pcfich_quad
=
0
;
pcfich_quad
<
4
;
pcfich_quad
++
)
{
reg_offset
=
(
pcfich_reg
[
pcfich_quad
]
*
4
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
pcfich_d_ptr
[
0
]
=
((
int16_t
*
)
&
rxdataF_comp
[
0
][
reg_offset
+
i
])[
0
];
// RE component
pcfich_d_ptr
[
1
]
=
((
int16_t
*
)
&
rxdataF_comp
[
0
][
reg_offset
+
i
])[
1
];
// IM component
#ifdef DEBUG_PCFICH
printf
(
"rx_pcfich: quad %d, i %d, offset %d => (%d,%d) => pcfich_d_ptr[0] %d
\n
"
,
pcfich_quad
,
i
,
reg_offset
+
i
,
((
int16_t
*
)
&
rxdataF_comp
[
0
][
reg_offset
+
i
])[
0
],
((
int16_t
*
)
&
rxdataF_comp
[
0
][
reg_offset
+
i
])[
1
],
pcfich_d_ptr
[
0
]);
#endif
pcfich_d_ptr
+=
2
;
}
/*
}
else { // ALAMOUTI
for (i=0;i<4;i+=2) {
pcfich_d_ptr[0] = 0;
pcfich_d_ptr[1] = 0;
pcfich_d_ptr[2] = 0;
pcfich_d_ptr[3] = 0;
for (j=0;j<frame_parms->nb_antennas_rx;j++) {
pcfich_d_ptr[0] += (((int16_t*)&rxdataF_comp[j][reg_offset+i])[0]+
((int16_t*)&rxdataF_comp[j+2][reg_offset+i+1])[0]); // RE component
pcfich_d_ptr[1] += (((int16_t*)&rxdataF_comp[j][reg_offset+i])[1] -
((int16_t*)&rxdataF_comp[j+2][reg_offset+i+1])[1]);// IM component
pcfich_d_ptr[2] += (((int16_t*)&rxdataF_comp[j][reg_offset+i+1])[0]-
((int16_t*)&rxdataF_comp[j+2][reg_offset+i])[0]); // RE component
pcfich_d_ptr[3] += (((int16_t*)&rxdataF_comp[j][reg_offset+i+1])[1] +
((int16_t*)&rxdataF_comp[j+2][reg_offset+i])[1]);// IM component
}
pcfich_d_ptr+=4;
}
*/
}
// pcfhich unscrambling
pcfich_unscrambling
(
frame_parms
,
subframe
,
pcfich_d
);
// pcfich detection
for
(
i
=
0
;
i
<
3
;
i
++
)
{
metric
=
0
;
for
(
j
=
0
;
j
<
32
;
j
++
)
{
// printf("pcfich_b[%d][%d] %d => pcfich_d[%d] %d\n",i,j,pcfich_b[i][j],j,pcfich_d[j]);
metric
+=
(
int32_t
)(((
pcfich_b
[
i
][
j
]
==
0
)
?
(
pcfich_d
[
j
])
:
(
-
pcfich_d
[
j
])));
}
#ifdef DEBUG_PCFICH
printf
(
"metric %d : %d
\n
"
,
i
,
metric
);
#endif
if
(
metric
>
old_metric
)
{
num_pdcch_symbols
=
1
+
i
;
old_metric
=
metric
;
}
}
#ifdef DEBUG_PCFICH
printf
(
"[PHY] PCFICH detected for %d PDCCH symbols
\n
"
,
num_pdcch_symbols
);
#endif
return
(
num_pdcch_symbols
);
}
openair1/PHY/LTE_UE_TRANSPORT/pch_ue.c
0 → 100644
View file @
fe95f0f4
/*
* 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
*/
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "assertions.h"
const
unsigned
int
Ttab
[
4
]
=
{
32
,
64
,
128
,
256
};
// This function implements the initialization of paging parameters for UE (See Section 7, 36.304)
// It must be called after setting IMSImod1024 during UE startup and after receiving SIB2
int
init_ue_paging_info
(
PHY_VARS_UE
*
ue
,
long
defaultPagingCycle
,
long
nB
)
{
LTE_DL_FRAME_PARMS
*
fp
=
&
ue
->
frame_parms
;
unsigned
int
T
=
Ttab
[
defaultPagingCycle
];
unsigned
int
N
=
(
nB
<=
2
)
?
T
:
(
T
>>
(
nB
-
2
));
unsigned
int
Ns
=
(
nB
<
2
)
?
(
1
<<
(
2
-
nB
))
:
1
;
unsigned
int
UE_ID
=
ue
->
IMSImod1024
;
unsigned
int
i_s
=
(
UE_ID
/
N
)
%
Ns
;
ue
->
PF
=
(
T
/
N
)
*
(
UE_ID
%
N
);
// This implements Section 7.2 from 36.304
if
(
Ns
==
1
)
ue
->
PO
=
(
fp
->
frame_type
==
FDD
)
?
9
:
0
;
else
if
(
Ns
==
2
)
ue
->
PO
=
(
fp
->
frame_type
==
FDD
)
?
(
4
+
(
5
*
i_s
))
:
(
5
*
i_s
);
else
if
(
Ns
==
4
)
ue
->
PO
=
(
fp
->
frame_type
==
FDD
)
?
(
4
*
(
i_s
&
1
)
+
(
5
*
(
i_s
>>
1
)))
:
((
i_s
&
1
)
+
(
5
*
(
i_s
>>
1
)));
else
AssertFatal
(
1
==
0
,
"init_ue_paging_info: Ns is %d
\n
"
,
Ns
);
return
(
0
);
}
openair1/PHY/LTE_UE_TRANSPORT/phich_ue.c
0 → 100644
View file @
fe95f0f4
/*
* 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
*/
/*! \file PHY/LTE_TRANSPORT/phich.c
* \brief Top-level routines for generating and decoding the PHICH/HI physical/transport channel V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "defs.h"
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/defs.h"
#include "T.h"
//#define DEBUG_PHICH 1
//extern unsigned short pcfich_reg[4];
//extern unsigned char pcfich_first_reg_idx;
//unsigned short phich_reg[MAX_NUM_PHICH_GROUPS][3];
uint8_t
rv_table
[
4
]
=
{
0
,
2
,
3
,
1
};
uint8_t
get_mi
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
subframe
)
{
// for FDD
if
(
frame_parms
->
frame_type
==
FDD
)
return
1
;
// for TDD
switch
(
frame_parms
->
tdd_config
)
{
case
0
:
if
((
subframe
==
0
)
||
(
subframe
==
5
))
return
(
2
);
else
return
(
1
);
break
;
case
1
:
if
((
subframe
==
0
)
||
(
subframe
==
5
))
return
(
0
);
else
return
(
1
);
break
;
case
2
:
if
((
subframe
==
3
)
||
(
subframe
==
8
))
return
(
1
);
else
return
(
0
);
break
;
case
3
:
if
((
subframe
==
0
)
||
(
subframe
==
8
)
||
(
subframe
==
9
))
return
(
1
);
else
return
(
0
);
break
;
case
4
:
if
((
subframe
==
8
)
||
(
subframe
==
9
))
return
(
1
);
else
return
(
0
);
break
;
case
5
:
if
(
subframe
==
8
)
return
(
1
);
else
return
(
0
);
break
;
case
6
:
return
(
1
);
break
;
default:
return
(
0
);
}
}
unsigned
char
subframe2_ul_harq
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
unsigned
char
subframe
)
{
if
(
frame_parms
->
frame_type
==
FDD
)
return
(
subframe
&
7
);
switch
(
frame_parms
->
tdd_config
)
{
case
3
:
if
(
(
subframe
==
8
)
||
(
subframe
==
9
)
)
{
return
(
subframe
-
8
);
}
else
if
(
subframe
==
0
)
return
(
2
);
else
{
LOG_E
(
PHY
,
"phich.c: subframe2_ul_harq, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
return
(
0
);
}
break
;
case
4
:
if
(
(
subframe
==
8
)
||
(
subframe
==
9
)
)
{
return
(
subframe
-
8
);
}
else
{
LOG_E
(
PHY
,
"phich.c: subframe2_ul_harq, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
return
(
0
);
}
break
;
}
return
(
0
);
}
int
phich_frame2_pusch_frame
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
frame
,
int
subframe
)
{
int
pusch_frame
;
if
(
frame_parms
->
frame_type
==
FDD
)
{
pusch_frame
=
subframe
<
4
?
frame
+
1024
-
1
:
frame
;
}
else
{
// Note this is not true, but it doesn't matter, the frame number is irrelevant for TDD!
pusch_frame
=
(
frame
);
}
//LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, subframe, pusch_frame);
return
pusch_frame
%
1024
;
}
uint8_t
phich_subframe2_pusch_subframe
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
subframe
)
{
uint8_t
pusch_subframe
=
255
;
if
(
frame_parms
->
frame_type
==
FDD
)
return
subframe
<
4
?
subframe
+
6
:
subframe
-
4
;
switch
(
frame_parms
->
tdd_config
)
{
case
0
:
if
(
subframe
==
0
)
pusch_subframe
=
(
3
);
else
if
(
subframe
==
5
)
{
pusch_subframe
=
(
8
);
}
else
if
(
subframe
==
6
)
pusch_subframe
=
(
2
);
else
if
(
subframe
==
1
)
pusch_subframe
=
(
7
);
else
{
AssertFatal
(
1
==
0
,
"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
break
;
case
1
:
if
(
subframe
==
6
)
pusch_subframe
=
(
2
);
else
if
(
subframe
==
9
)
pusch_subframe
=
(
3
);
else
if
(
subframe
==
1
)
pusch_subframe
=
(
7
);
else
if
(
subframe
==
4
)
pusch_subframe
=
(
8
);
else
{
AssertFatal
(
1
==
0
,
"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
break
;
case
2
:
if
(
subframe
==
8
)
pusch_subframe
=
(
2
);
else
if
(
subframe
==
3
)
pusch_subframe
=
(
7
);
else
{
AssertFatal
(
1
==
0
,
"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
break
;
case
3
:
if
(
(
subframe
==
8
)
||
(
subframe
==
9
)
)
{
pusch_subframe
=
(
subframe
-
6
);
}
else
if
(
subframe
==
0
)
pusch_subframe
=
(
4
);
else
{
AssertFatal
(
1
==
0
,
"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
break
;
case
4
:
if
(
(
subframe
==
8
)
||
(
subframe
==
9
)
)
{
pusch_subframe
=
(
subframe
-
6
);
}
else
{
AssertFatal
(
1
==
0
,
"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
break
;
case
5
:
if
(
subframe
==
8
)
{
pusch_subframe
=
(
2
);
}
else
{
AssertFatal
(
1
==
0
,
"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
break
;
case
6
:
if
(
subframe
==
6
)
{
pusch_subframe
=
(
2
);
}
else
if
(
subframe
==
9
)
{
pusch_subframe
=
(
3
);
}
else
if
(
subframe
==
0
)
{
pusch_subframe
=
(
4
);
}
else
if
(
subframe
==
1
)
{
pusch_subframe
=
(
7
);
}
else
if
(
subframe
==
5
)
{
pusch_subframe
=
(
8
);
}
else
{
AssertFatal
(
1
==
0
,
"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d
\n
"
,
subframe
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
break
;
default:
AssertFatal
(
1
==
0
,
"no implementation for TDD UL/DL-config = %d!
\n
"
,
frame_parms
->
tdd_config
);
pusch_subframe
=
(
0
);
}
LOG_D
(
PHY
,
"subframe %d: PUSCH subframe = %d
\n
"
,
subframe
,
pusch_subframe
);
return
pusch_subframe
;
}
int
check_pcfich
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint16_t
reg
)
{
if
((
reg
==
frame_parms
->
pcfich_reg
[
0
])
||
(
reg
==
frame_parms
->
pcfich_reg
[
1
])
||
(
reg
==
frame_parms
->
pcfich_reg
[
2
])
||
(
reg
==
frame_parms
->
pcfich_reg
[
3
]))
return
(
1
);
return
(
0
);
}
void
generate_phich_reg_mapping
(
LTE_DL_FRAME_PARMS
*
frame_parms
)
{
unsigned
short
n0
=
(
frame_parms
->
N_RB_DL
*
2
)
-
4
;
// 2 REG per RB less the 4 used by PCFICH in first symbol
unsigned
short
n1
=
(
frame_parms
->
N_RB_DL
*
3
);
// 3 REG per RB in second and third symbol
unsigned
short
n2
=
n1
;
unsigned
short
mprime
=
0
;
unsigned
short
Ngroup_PHICH
;
// uint16_t *phich_reg = frame_parms->phich_reg;
uint16_t
*
pcfich_reg
=
frame_parms
->
pcfich_reg
;
// compute Ngroup_PHICH (see formula at beginning of Section 6.9 in 36-211
Ngroup_PHICH
=
(
frame_parms
->
phich_config_common
.
phich_resource
*
frame_parms
->
N_RB_DL
)
/
48
;
if
(((
frame_parms
->
phich_config_common
.
phich_resource
*
frame_parms
->
N_RB_DL
)
%
48
)
>
0
)
Ngroup_PHICH
++
;
// check if Extended prefix
if
(
frame_parms
->
Ncp
==
1
)
{
Ngroup_PHICH
<<=
1
;
}
#ifdef DEBUG_PHICH
LOG_D
(
PHY
,
"Ngroup_PHICH %d (phich_config_common.phich_resource %d,phich_config_common.phich_duration %s, NidCell %d,Ncp %d, frame_type %d), smallest pcfich REG %d, n0 %d, n1 %d (first PHICH REG %d)
\n
"
,
((
frame_parms
->
Ncp
==
NORMAL
)
?
Ngroup_PHICH
:
(
Ngroup_PHICH
>>
1
)),
frame_parms
->
phich_config_common
.
phich_resource
,
frame_parms
->
phich_config_common
.
phich_duration
==
normal
?
"normal"
:
"extended"
,
frame_parms
->
Nid_cell
,
frame_parms
->
Ncp
,
frame_parms
->
frame_type
,
pcfich_reg
[
frame_parms
->
pcfich_first_reg_idx
],
n0
,
n1
,
((
frame_parms
->
Nid_cell
))
%
n0
);
#endif
// This is the algorithm from Section 6.9.3 in 36-211, it works only for normal PHICH duration for now ...
for
(
mprime
=
0
;
mprime
<
((
frame_parms
->
Ncp
==
NORMAL
)
?
Ngroup_PHICH
:
(
Ngroup_PHICH
>>
1
));
mprime
++
)
{
if
(
frame_parms
->
phich_config_common
.
phich_duration
==
normal
)
{
// normal PHICH duration
frame_parms
->
phich_reg
[
mprime
][
0
]
=
(
frame_parms
->
Nid_cell
+
mprime
)
%
n0
;
if
(
frame_parms
->
phich_reg
[
mprime
][
0
]
>=
pcfich_reg
[
frame_parms
->
pcfich_first_reg_idx
])
frame_parms
->
phich_reg
[
mprime
][
0
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
0
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
1
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
0
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
0
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
2
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
0
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
0
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
3
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
0
]
++
;
frame_parms
->
phich_reg
[
mprime
][
1
]
=
(
frame_parms
->
Nid_cell
+
mprime
+
(
n0
/
3
))
%
n0
;
if
(
frame_parms
->
phich_reg
[
mprime
][
1
]
>=
pcfich_reg
[
frame_parms
->
pcfich_first_reg_idx
])
frame_parms
->
phich_reg
[
mprime
][
1
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
1
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
1
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
1
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
1
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
2
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
1
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
1
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
3
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
1
]
++
;
frame_parms
->
phich_reg
[
mprime
][
2
]
=
(
frame_parms
->
Nid_cell
+
mprime
+
(
2
*
n0
/
3
))
%
n0
;
if
(
frame_parms
->
phich_reg
[
mprime
][
2
]
>=
pcfich_reg
[
frame_parms
->
pcfich_first_reg_idx
])
frame_parms
->
phich_reg
[
mprime
][
2
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
2
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
1
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
2
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
2
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
2
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
2
]
++
;
if
(
frame_parms
->
phich_reg
[
mprime
][
2
]
>=
pcfich_reg
[(
frame_parms
->
pcfich_first_reg_idx
+
3
)
&
3
])
frame_parms
->
phich_reg
[
mprime
][
2
]
++
;
#ifdef DEBUG_PHICH
printf
(
"phich_reg :%d => %d,%d,%d
\n
"
,
mprime
,
frame_parms
->
phich_reg
[
mprime
][
0
],
frame_parms
->
phich_reg
[
mprime
][
1
],
frame_parms
->
phich_reg
[
mprime
][
2
]);
#endif
}
else
{
// extended PHICH duration
frame_parms
->
phich_reg
[
mprime
<<
1
][
0
]
=
(
frame_parms
->
Nid_cell
+
mprime
)
%
n0
;
frame_parms
->
phich_reg
[
1
+
(
mprime
<<
1
)][
0
]
=
(
frame_parms
->
Nid_cell
+
mprime
)
%
n0
;
frame_parms
->
phich_reg
[
mprime
<<
1
][
1
]
=
((
frame_parms
->
Nid_cell
*
n1
/
n0
)
+
mprime
+
(
n1
/
3
))
%
n1
;
frame_parms
->
phich_reg
[
mprime
<<
1
][
2
]
=
((
frame_parms
->
Nid_cell
*
n2
/
n0
)
+
mprime
+
(
2
*
n2
/
3
))
%
n2
;
frame_parms
->
phich_reg
[
1
+
(
mprime
<<
1
)][
1
]
=
((
frame_parms
->
Nid_cell
*
n1
/
n0
)
+
mprime
+
(
n1
/
3
))
%
n1
;
frame_parms
->
phich_reg
[
1
+
(
mprime
<<
1
)][
2
]
=
((
frame_parms
->
Nid_cell
*
n2
/
n0
)
+
mprime
+
(
2
*
n2
/
3
))
%
n2
;
//#ifdef DEBUG_PHICH
printf
(
"phich_reg :%d => %d,%d,%d
\n
"
,
mprime
<<
1
,
frame_parms
->
phich_reg
[
mprime
<<
1
][
0
],
frame_parms
->
phich_reg
[
mprime
][
1
],
frame_parms
->
phich_reg
[
mprime
][
2
]);
printf
(
"phich_reg :%d => %d,%d,%d
\n
"
,
1
+
(
mprime
<<
1
),
frame_parms
->
phich_reg
[
1
+
(
mprime
<<
1
)][
0
],
frame_parms
->
phich_reg
[
1
+
(
mprime
<<
1
)][
1
],
frame_parms
->
phich_reg
[
1
+
(
mprime
<<
1
)][
2
]);
//#endif
}
}
// mprime loop
}
// num_pdcch_symbols loop
void
generate_phich_emul
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
HI
,
uint8_t
subframe
)
{
}
int32_t
alam_bpsk_perm1
[
4
]
=
{
2
,
1
,
4
,
3
};
// -conj(x) 1 (-1-j) -> 2 (1-j), 2->1, 3 (-1+j) -> (4) 1+j, 4->3
int32_t
alam_bpsk_perm2
[
4
]
=
{
3
,
4
,
2
,
1
};
// conj(x) 1 (-1-j) -> 3 (-1+j), 3->1, 2 (1-j) -> 4 (1+j), 4->2
// This routine generates the PHICH
void
generate_phich
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int16_t
amp
,
uint8_t
nseq_PHICH
,
uint8_t
ngroup_PHICH
,
uint8_t
HI
,
uint8_t
subframe
,
int32_t
**
y
)
{
int16_t
d
[
24
],
*
dp
;
// unsigned int i,aa;
unsigned
int
re_offset
;
int16_t
y0_16
[
8
],
y1_16
[
8
];
int16_t
*
y0
,
*
y1
;
// scrambling
uint32_t
x1
,
x2
,
s
=
0
;
uint8_t
reset
=
1
;
int16_t
cs
[
12
];
uint32_t
i
,
i2
,
i3
,
m
,
j
;
int16_t
gain_lin_QPSK
;
uint32_t
subframe_offset
=
((
frame_parms
->
Ncp
==
0
)
?
14
:
12
)
*
frame_parms
->
ofdm_symbol_size
*
subframe
;
memset
(
d
,
0
,
24
*
sizeof
(
int16_t
));
if
(
frame_parms
->
nb_antenna_ports_eNB
==
1
)
gain_lin_QPSK
=
(
int16_t
)(((
int32_t
)
amp
*
ONE_OVER_SQRT2_Q15
)
>>
15
);
else
gain_lin_QPSK
=
amp
/
2
;
//printf("PHICH : gain_lin_QPSK %d\n",gain_lin_QPSK);
// BPSK modulation of HI input (to be repeated 3 times, 36-212 Section 5.3.5, p. 56 in v8.6)
if
(
HI
>
0
)
HI
=
1
;
// c = (1-(2*HI))*SSS_AMP;
// x1 is set in lte_gold_generic
x2
=
(((
subframe
+
1
)
*
((
frame_parms
->
Nid_cell
<<
1
)
+
1
))
<<
9
)
+
frame_parms
->
Nid_cell
;
s
=
lte_gold_generic
(
&
x1
,
&
x2
,
reset
);
// compute scrambling sequence
for
(
i
=
0
;
i
<
12
;
i
++
)
{
cs
[
i
]
=
(
uint8_t
)((
s
>>
(
i
&
0x1f
))
&
1
);
cs
[
i
]
=
(
cs
[
i
]
==
0
)
?
(
1
-
(
HI
<<
1
))
:
((
HI
<<
1
)
-
1
);
}
if
(
frame_parms
->
Ncp
==
0
)
{
// Normal Cyclic Prefix
// printf("Doing PHICH : Normal CP, subframe %d\n",subframe);
// 12 output symbols (Msymb)
for
(
i
=
0
,
i2
=
0
,
i3
=
0
;
i
<
3
;
i
++
,
i2
+=
4
,
i3
+=
8
)
{
switch
(
nseq_PHICH
)
{
case
0
:
// +1 +1 +1 +1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
1
:
// +1 -1 +1 -1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
break
;
case
2
:
// +1 +1 -1 -1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
break
;
case
3
:
// +1 -1 -1 +1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
4
:
// +j +j +j +j
d
[
i3
]
=
-
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
5
:
// +j -j +j -j
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
i3
]
=
-
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
6
:
// +j +j -j -j
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
i3
]
=
-
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
7
:
// +j -j -j +j
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
d
[
i3
]
=
-
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
break
;
default:
AssertFatal
(
1
==
0
,
"phich_coding.c: Illegal PHICH Number
\n
"
);
}
// nseq_PHICH
}
#ifdef DEBUG_PHICH
LOG_D
(
PHY
,
"[PUSCH 0]PHICH d = "
);
for
(
i
=
0
;
i
<
24
;
i
+=
2
)
LOG_D
(
PHY
,
"(%d,%d)"
,
d
[
i
],
d
[
i
+
1
]);
LOG_D
(
PHY
,
"
\n
"
);
#endif
// modulation here
if
(
frame_parms
->
nb_antenna_ports_eNB
!=
1
)
{
// do Alamouti precoding here
// Symbol 0
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
0
]
*
6
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y1
=
(
int16_t
*
)
&
y
[
1
][
re_offset
+
subframe_offset
];
// first antenna position n -> x0
y0_16
[
0
]
=
d
[
0
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
1
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
0
]
=
-
d
[
2
]
*
gain_lin_QPSK
;
y1_16
[
1
]
=
d
[
3
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
2
]
=
-
y1_16
[
0
];
y0_16
[
3
]
=
y1_16
[
1
];
y1_16
[
2
]
=
y0_16
[
0
];
y1_16
[
3
]
=
-
y0_16
[
1
];
// first antenna position n -> x0
y0_16
[
4
]
=
d
[
4
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
5
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
4
]
=
-
d
[
6
]
*
gain_lin_QPSK
;
y1_16
[
5
]
=
d
[
7
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
6
]
=
-
y1_16
[
4
];
y0_16
[
7
]
=
y1_16
[
5
];
y1_16
[
6
]
=
y0_16
[
4
];
y1_16
[
7
]
=
-
y0_16
[
5
];
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
];
y1
[
j
]
+=
y1_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
];
y1
[
j
+
1
]
+=
y1_16
[
m
++
];
}
}
// Symbol 1
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
1
]
*
6
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y1
=
(
int16_t
*
)
&
y
[
1
][
re_offset
+
subframe_offset
];
// first antenna position n -> x0
y0_16
[
0
]
=
d
[
8
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
9
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
0
]
=
-
d
[
10
]
*
gain_lin_QPSK
;
y1_16
[
1
]
=
d
[
11
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
2
]
=
-
y1_16
[
0
];
y0_16
[
3
]
=
y1_16
[
1
];
y1_16
[
2
]
=
y0_16
[
0
];
y1_16
[
3
]
=
-
y0_16
[
1
];
// first antenna position n -> x0
y0_16
[
4
]
=
d
[
12
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
13
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
4
]
=
-
d
[
14
]
*
gain_lin_QPSK
;
y1_16
[
5
]
=
d
[
15
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
6
]
=
-
y1_16
[
4
];
y0_16
[
7
]
=
y1_16
[
5
];
y1_16
[
6
]
=
y0_16
[
4
];
y1_16
[
7
]
=
-
y0_16
[
5
];
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
];
y1
[
j
]
+=
y1_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
];
y1
[
j
+
1
]
+=
y1_16
[
m
++
];
}
}
// Symbol 2
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
2
]
*
6
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y1
=
(
int16_t
*
)
&
y
[
1
][
re_offset
+
subframe_offset
];
// first antenna position n -> x0
y0_16
[
0
]
=
d
[
16
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
17
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
0
]
=
-
d
[
18
]
*
gain_lin_QPSK
;
y1_16
[
1
]
=
d
[
19
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
2
]
=
-
y1_16
[
0
];
y0_16
[
3
]
=
y1_16
[
1
];
y1_16
[
2
]
=
y0_16
[
0
];
y1_16
[
3
]
=
-
y0_16
[
1
];
// first antenna position n -> x0
y0_16
[
4
]
=
d
[
20
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
21
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
4
]
=
-
d
[
22
]
*
gain_lin_QPSK
;
y1_16
[
5
]
=
d
[
23
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
6
]
=
-
y1_16
[
4
];
y0_16
[
7
]
=
y1_16
[
5
];
y1_16
[
6
]
=
y0_16
[
4
];
y1_16
[
7
]
=
-
y0_16
[
5
];
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
];
y1
[
j
]
+=
y1_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
];
y1
[
j
+
1
]
+=
y1_16
[
m
++
];
}
}
}
// nb_antenna_ports_eNB
else
{
// Symbol 0
// printf("[PUSCH 0]PHICH REG %d\n",frame_parms->phich_reg[ngroup_PHICH][0]);
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
0
]
*
6
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
// printf("y0 %p\n",y0);
y0_16
[
0
]
=
d
[
0
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
1
]
*
gain_lin_QPSK
;
y0_16
[
2
]
=
d
[
2
]
*
gain_lin_QPSK
;
y0_16
[
3
]
=
d
[
3
]
*
gain_lin_QPSK
;
y0_16
[
4
]
=
d
[
4
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
5
]
*
gain_lin_QPSK
;
y0_16
[
6
]
=
d
[
6
]
*
gain_lin_QPSK
;
y0_16
[
7
]
=
d
[
7
]
*
gain_lin_QPSK
;
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
++
];
}
}
// Symbol 1
// printf("[PUSCH 0]PHICH REG %d\n",frame_parms->phich_reg[ngroup_PHICH][1]);
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
1
]
*
6
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y0_16
[
0
]
=
d
[
8
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
9
]
*
gain_lin_QPSK
;
y0_16
[
2
]
=
d
[
10
]
*
gain_lin_QPSK
;
y0_16
[
3
]
=
d
[
11
]
*
gain_lin_QPSK
;
y0_16
[
4
]
=
d
[
12
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
13
]
*
gain_lin_QPSK
;
y0_16
[
6
]
=
d
[
14
]
*
gain_lin_QPSK
;
y0_16
[
7
]
=
d
[
15
]
*
gain_lin_QPSK
;
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
++
];
}
}
// Symbol 2
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
2
]
*
6
);
// printf("[PUSCH 0]PHICH REG %d\n",frame_parms->phich_reg[ngroup_PHICH][2]);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y0_16
[
0
]
=
d
[
16
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
17
]
*
gain_lin_QPSK
;
y0_16
[
2
]
=
d
[
18
]
*
gain_lin_QPSK
;
y0_16
[
3
]
=
d
[
19
]
*
gain_lin_QPSK
;
y0_16
[
4
]
=
d
[
20
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
21
]
*
gain_lin_QPSK
;
y0_16
[
6
]
=
d
[
22
]
*
gain_lin_QPSK
;
y0_16
[
7
]
=
d
[
23
]
*
gain_lin_QPSK
;
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
++
];
}
}
/*
for (i=0;i<512;i++)
printf("re %d (%d): %d,%d\n",i,subframe_offset+i,((int16_t*)&y[0][subframe_offset+i])[0],((int16_t*)&y[0][subframe_offset+i])[1]);
*/
}
// nb_antenna_ports_eNB
}
else
{
// extended prefix
// 6 output symbols
if
((
ngroup_PHICH
&
1
)
==
1
)
dp
=
&
d
[
4
];
else
dp
=
d
;
switch
(
nseq_PHICH
)
{
case
0
:
// +1 +1
dp
[
0
]
=
cs
[
0
];
dp
[
2
]
=
cs
[
1
];
dp
[
8
]
=
cs
[
2
];
dp
[
10
]
=
cs
[
3
];
dp
[
16
]
=
cs
[
4
];
dp
[
18
]
=
cs
[
5
];
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
cs
[
5
];
break
;
case
1
:
// +1 -1
dp
[
0
]
=
cs
[
0
];
dp
[
2
]
=
-
cs
[
1
];
dp
[
8
]
=
cs
[
2
];
dp
[
10
]
=
-
cs
[
3
];
dp
[
16
]
=
cs
[
4
];
dp
[
18
]
=
-
cs
[
5
];
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
-
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
-
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
-
cs
[
5
];
break
;
case
2
:
// +j +j
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
cs
[
5
];
dp
[
0
]
=
-
cs
[
0
];
dp
[
2
]
=
-
cs
[
1
];
dp
[
8
]
=
-
cs
[
2
];
dp
[
10
]
=
-
cs
[
3
];
dp
[
16
]
=
-
cs
[
4
];
dp
[
18
]
=
-
cs
[
5
];
break
;
case
3
:
// +j -j
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
-
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
-
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
-
cs
[
5
];
dp
[
0
]
=
-
cs
[
0
];
dp
[
2
]
=
cs
[
1
];
dp
[
8
]
=
-
cs
[
2
];
dp
[
10
]
=
cs
[
3
];
dp
[
16
]
=
-
cs
[
4
];
dp
[
18
]
=
cs
[
5
];
break
;
default:
AssertFatal
(
1
==
0
,
"phich_coding.c: Illegal PHICH Number
\n
"
);
}
if
(
frame_parms
->
nb_antenna_ports_eNB
!=
1
)
{
// do Alamouti precoding here
// Symbol 0
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
0
]
*
6
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y1
=
(
int16_t
*
)
&
y
[
1
][
re_offset
+
subframe_offset
];
// first antenna position n -> x0
y0_16
[
0
]
=
d
[
0
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
1
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
0
]
=
-
d
[
2
]
*
gain_lin_QPSK
;
y1_16
[
1
]
=
d
[
3
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
2
]
=
-
y1_16
[
0
];
y0_16
[
3
]
=
y1_16
[
1
];
y1_16
[
2
]
=
y0_16
[
0
];
y1_16
[
3
]
=
-
y0_16
[
1
];
// first antenna position n -> x0
y0_16
[
4
]
=
d
[
4
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
5
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
4
]
=
-
d
[
6
]
*
gain_lin_QPSK
;
y1_16
[
5
]
=
d
[
7
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
6
]
=
-
y1_16
[
4
];
y0_16
[
7
]
=
y1_16
[
5
];
y1_16
[
6
]
=
y0_16
[
4
];
y1_16
[
7
]
=
-
y0_16
[
5
];
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
];
y1
[
j
]
+=
y1_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
];
y1
[
j
+
1
]
+=
y1_16
[
m
++
];
}
}
// Symbol 1
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
1
]
<<
2
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
re_offset
+=
(
frame_parms
->
ofdm_symbol_size
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y1
=
(
int16_t
*
)
&
y
[
1
][
re_offset
+
subframe_offset
];
// first antenna position n -> x0
y0_16
[
0
]
=
d
[
8
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
9
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
0
]
=
-
d
[
10
]
*
gain_lin_QPSK
;
y1_16
[
1
]
=
d
[
11
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
2
]
=
-
y1_16
[
0
];
y0_16
[
3
]
=
y1_16
[
1
];
y1_16
[
2
]
=
y0_16
[
0
];
y1_16
[
3
]
=
-
y0_16
[
1
];
// first antenna position n -> x0
y0_16
[
4
]
=
d
[
12
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
13
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
4
]
=
-
d
[
14
]
*
gain_lin_QPSK
;
y1_16
[
5
]
=
d
[
15
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
6
]
=
-
y1_16
[
4
];
y0_16
[
7
]
=
y1_16
[
5
];
y1_16
[
6
]
=
y0_16
[
4
];
y1_16
[
7
]
=
-
y0_16
[
5
];
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
4
;
i
++
,
j
+=
2
)
{
y0
[
j
]
+=
y0_16
[
m
];
y1
[
j
]
+=
y1_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
];
y1
[
j
+
1
]
+=
y1_16
[
m
++
];
}
// Symbol 2
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
2
]
<<
2
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
re_offset
+=
(
frame_parms
->
ofdm_symbol_size
<<
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y1
=
(
int16_t
*
)
&
y
[
1
][
re_offset
+
subframe_offset
];
// first antenna position n -> x0
y0_16
[
0
]
=
d
[
16
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
17
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
0
]
=
-
d
[
18
]
*
gain_lin_QPSK
;
y1_16
[
1
]
=
d
[
19
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
2
]
=
-
y1_16
[
0
];
y0_16
[
3
]
=
y1_16
[
1
];
y1_16
[
2
]
=
y0_16
[
0
];
y1_16
[
3
]
=
-
y0_16
[
1
];
// first antenna position n -> x0
y0_16
[
4
]
=
d
[
20
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
21
]
*
gain_lin_QPSK
;
// second antenna position n -> -x1*
y1_16
[
4
]
=
-
d
[
22
]
*
gain_lin_QPSK
;
y1_16
[
5
]
=
d
[
23
]
*
gain_lin_QPSK
;
// fill in the rest of the ALAMOUTI precoding
y0_16
[
6
]
=
-
y1_16
[
4
];
y0_16
[
7
]
=
y1_16
[
5
];
y1_16
[
6
]
=
y0_16
[
4
];
y1_16
[
7
]
=
-
y0_16
[
5
];
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
4
;
i
++
,
j
+=
2
)
{
y0
[
j
]
+=
y0_16
[
m
];
y1
[
j
]
+=
y1_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
];
y1
[
j
+
1
]
+=
y1_16
[
m
++
];
}
}
else
{
// Symbol 0
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
0
]
*
6
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y0_16
[
0
]
=
d
[
0
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
1
]
*
gain_lin_QPSK
;
y0_16
[
2
]
=
d
[
2
]
*
gain_lin_QPSK
;
y0_16
[
3
]
=
d
[
3
]
*
gain_lin_QPSK
;
y0_16
[
4
]
=
d
[
4
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
5
]
*
gain_lin_QPSK
;
y0_16
[
6
]
=
d
[
6
]
*
gain_lin_QPSK
;
y0_16
[
7
]
=
d
[
7
]
*
gain_lin_QPSK
;
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
6
;
i
++
,
j
+=
2
)
{
if
((
i
!=
(
frame_parms
->
nushift
))
&&
(
i
!=
(
frame_parms
->
nushift
+
3
)))
{
y0
[
j
]
+=
y0_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
++
];
}
}
// Symbol 1
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
1
]
<<
2
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
re_offset
+=
(
frame_parms
->
ofdm_symbol_size
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y0_16
[
0
]
=
d
[
8
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
9
]
*
gain_lin_QPSK
;
y0_16
[
2
]
=
d
[
10
]
*
gain_lin_QPSK
;
y0_16
[
3
]
=
d
[
11
]
*
gain_lin_QPSK
;
y0_16
[
4
]
=
d
[
12
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
13
]
*
gain_lin_QPSK
;
y0_16
[
6
]
=
d
[
14
]
*
gain_lin_QPSK
;
y0_16
[
7
]
=
d
[
15
]
*
gain_lin_QPSK
;
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
4
;
i
++
,
j
+=
2
)
{
y0
[
j
]
+=
y0_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
++
];
}
// Symbol 2
re_offset
=
frame_parms
->
first_carrier_offset
+
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
2
]
<<
2
);
if
(
re_offset
>
frame_parms
->
ofdm_symbol_size
)
re_offset
-=
(
frame_parms
->
ofdm_symbol_size
-
1
);
re_offset
+=
(
frame_parms
->
ofdm_symbol_size
<<
1
);
y0
=
(
int16_t
*
)
&
y
[
0
][
re_offset
+
subframe_offset
];
y0_16
[
0
]
=
d
[
16
]
*
gain_lin_QPSK
;
y0_16
[
1
]
=
d
[
17
]
*
gain_lin_QPSK
;
y0_16
[
2
]
=
d
[
18
]
*
gain_lin_QPSK
;
y0_16
[
3
]
=
d
[
19
]
*
gain_lin_QPSK
;
y0_16
[
4
]
=
d
[
20
]
*
gain_lin_QPSK
;
y0_16
[
5
]
=
d
[
21
]
*
gain_lin_QPSK
;
y0_16
[
6
]
=
d
[
22
]
*
gain_lin_QPSK
;
y0_16
[
7
]
=
d
[
23
]
*
gain_lin_QPSK
;
for
(
i
=
0
,
j
=
0
,
m
=
0
;
i
<
4
;
i
++
)
{
y0
[
j
]
+=
y0_16
[
m
++
];
y0
[
j
+
1
]
+=
y0_16
[
m
++
];
}
}
// nb_antenna_ports_eNB
}
// normal/extended prefix
}
// This routine demodulates the PHICH and updates PUSCH/ULSCH parameters
void
rx_phich
(
PHY_VARS_UE
*
ue
,
UE_rxtx_proc_t
*
proc
,
uint8_t
subframe
,
uint8_t
eNB_id
)
{
LTE_DL_FRAME_PARMS
*
frame_parms
=&
ue
->
frame_parms
;
LTE_UE_PDCCH
**
pdcch_vars
=
&
ue
->
pdcch_vars
[
ue
->
current_thread_id
[
subframe
]][
eNB_id
];
// uint8_t HI;
uint8_t
harq_pid
=
phich_subframe_to_harq_pid
(
frame_parms
,
proc
->
frame_rx
,
subframe
);
LTE_UE_ULSCH_t
*
ulsch
=
ue
->
ulsch
[
eNB_id
];
int16_t
phich_d
[
24
],
*
phich_d_ptr
,
HI16
;
// unsigned int i,aa;
int8_t
d
[
24
],
*
dp
;
uint16_t
reg_offset
;
// scrambling
uint32_t
x1
,
x2
,
s
=
0
;
uint8_t
reset
=
1
;
int16_t
cs
[
12
];
uint32_t
i
,
i2
,
i3
,
phich_quad
;
int32_t
**
rxdataF_comp
=
pdcch_vars
[
eNB_id
]
->
rxdataF_comp
;
uint8_t
Ngroup_PHICH
,
ngroup_PHICH
,
nseq_PHICH
;
uint8_t
NSF_PHICH
=
4
;
uint8_t
pusch_subframe
;
int8_t
delta_PUSCH_acc
[
4
]
=
{
-
1
,
0
,
1
,
3
};
// check if we're expecting a PHICH in this subframe
LOG_D
(
PHY
,
"[UE %d][PUSCH %d] Frame %d subframe %d PHICH RX
\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
,
subframe
);
if
(
!
ulsch
)
return
;
LOG_D
(
PHY
,
"[UE %d][PUSCH %d] Frame %d subframe %d PHICH RX Status: %d
\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
,
subframe
,
ulsch
->
harq_processes
[
harq_pid
]
->
status
);
if
(
ulsch
->
harq_processes
[
harq_pid
]
->
status
==
ACTIVE
)
{
LOG_D
(
PHY
,
"[UE %d][PUSCH %d] Frame %d subframe %d PHICH RX ACTIVE
\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
,
subframe
);
Ngroup_PHICH
=
(
frame_parms
->
phich_config_common
.
phich_resource
*
frame_parms
->
N_RB_DL
)
/
48
;
if
(((
frame_parms
->
phich_config_common
.
phich_resource
*
frame_parms
->
N_RB_DL
)
%
48
)
>
0
)
Ngroup_PHICH
++
;
if
(
frame_parms
->
Ncp
==
1
)
NSF_PHICH
=
2
;
ngroup_PHICH
=
(
ulsch
->
harq_processes
[
harq_pid
]
->
first_rb
+
ulsch
->
harq_processes
[
harq_pid
]
->
n_DMRS
)
%
Ngroup_PHICH
;
if
((
frame_parms
->
tdd_config
==
0
)
&&
(
frame_parms
->
frame_type
==
TDD
)
)
{
pusch_subframe
=
phich_subframe2_pusch_subframe
(
frame_parms
,
subframe
);
if
((
pusch_subframe
==
4
)
||
(
pusch_subframe
==
9
))
ngroup_PHICH
+=
Ngroup_PHICH
;
}
nseq_PHICH
=
((
ulsch
->
harq_processes
[
harq_pid
]
->
first_rb
/
Ngroup_PHICH
)
+
ulsch
->
harq_processes
[
harq_pid
]
->
n_DMRS
)
%
(
2
*
NSF_PHICH
);
}
else
{
LOG_D
(
PHY
,
"[UE %d][PUSCH %d] Frame %d subframe %d PHICH RX %s
\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
,
subframe
,
(
ulsch
->
harq_processes
[
harq_pid
]
->
status
==
SCH_IDLE
?
"SCH_IDLE"
:
(
ulsch
->
harq_processes
[
harq_pid
]
->
status
==
ACTIVE
?
"ACTIVE"
:
(
ulsch
->
harq_processes
[
harq_pid
]
->
status
==
CBA_ACTIVE
?
"CBA_ACTIVE"
:
(
ulsch
->
harq_processes
[
harq_pid
]
->
status
==
DISABLED
?
"DISABLED"
:
"UNKNOWN"
)))));
return
;
}
memset
(
d
,
0
,
24
*
sizeof
(
int8_t
));
phich_d_ptr
=
phich_d
;
// x1 is set in lte_gold_generic
x2
=
(((
subframe
+
1
)
*
((
frame_parms
->
Nid_cell
<<
1
)
+
1
))
<<
9
)
+
frame_parms
->
Nid_cell
;
s
=
lte_gold_generic
(
&
x1
,
&
x2
,
reset
);
// compute scrambling sequence
for
(
i
=
0
;
i
<
12
;
i
++
)
{
cs
[
i
]
=
1
-
(((
s
>>
(
i
&
0x1f
))
&
1
)
<<
1
);
}
if
(
frame_parms
->
Ncp
==
0
)
{
// Normal Cyclic Prefix
// 12 output symbols (Msymb)
for
(
i
=
0
,
i2
=
0
,
i3
=
0
;
i
<
3
;
i
++
,
i2
+=
4
,
i3
+=
8
)
{
switch
(
nseq_PHICH
)
{
case
0
:
// +1 +1 +1 +1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
1
:
// +1 -1 +1 -1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
break
;
case
2
:
// +1 +1 -1 -1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
break
;
case
3
:
// +1 -1 -1 +1
d
[
i3
]
=
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
4
:
// +j +j +j +j
d
[
i3
]
=
-
cs
[
i2
];
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
5
:
// +j -j +j -j
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
5
+
i3
]
=
cs
[
2
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
i3
]
=
-
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
6
:
// +j +j -j -j
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
3
+
i3
]
=
cs
[
1
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
7
+
i3
]
=
-
cs
[
3
+
i2
];
d
[
i3
]
=
-
cs
[
i2
];
d
[
2
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
cs
[
3
+
i2
];
break
;
case
7
:
// +j -j -j +j
d
[
1
+
i3
]
=
cs
[
i2
];
d
[
3
+
i3
]
=
-
cs
[
1
+
i2
];
d
[
5
+
i3
]
=
-
cs
[
2
+
i2
];
d
[
7
+
i3
]
=
cs
[
3
+
i2
];
d
[
i3
]
=
-
cs
[
i2
];
d
[
2
+
i3
]
=
cs
[
1
+
i2
];
d
[
4
+
i3
]
=
cs
[
2
+
i2
];
d
[
6
+
i3
]
=
-
cs
[
3
+
i2
];
break
;
default:
AssertFatal
(
1
==
0
,
"phich_coding.c: Illegal PHICH Number
\n
"
);
}
// nseq_PHICH
}
#ifdef DEBUG_PHICH
LOG_D
(
PHY
,
"PHICH =>"
);
for
(
i
=
0
;
i
<
24
;
i
++
)
{
LOG_D
(
PHY
,
"%2d,"
,
d
[
i
]);
}
LOG_D
(
PHY
,
"
\n
"
);
#endif
// demodulation here
}
else
{
// extended prefix
// 6 output symbols
if
((
ngroup_PHICH
&
1
)
==
1
)
dp
=
&
d
[
4
];
else
dp
=
d
;
switch
(
nseq_PHICH
)
{
case
0
:
// +1 +1
dp
[
0
]
=
cs
[
0
];
dp
[
2
]
=
cs
[
1
];
dp
[
8
]
=
cs
[
2
];
dp
[
10
]
=
cs
[
3
];
dp
[
16
]
=
cs
[
4
];
dp
[
18
]
=
cs
[
5
];
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
cs
[
5
];
break
;
case
1
:
// +1 -1
dp
[
0
]
=
cs
[
0
];
dp
[
2
]
=
-
cs
[
1
];
dp
[
8
]
=
cs
[
2
];
dp
[
10
]
=
-
cs
[
3
];
dp
[
16
]
=
cs
[
4
];
dp
[
18
]
=
-
cs
[
5
];
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
-
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
-
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
-
cs
[
5
];
break
;
case
2
:
// +j +j
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
cs
[
5
];
dp
[
0
]
=
-
cs
[
0
];
dp
[
2
]
=
-
cs
[
1
];
dp
[
8
]
=
-
cs
[
2
];
dp
[
10
]
=
-
cs
[
3
];
dp
[
16
]
=
-
cs
[
4
];
dp
[
18
]
=
-
cs
[
5
];
break
;
case
3
:
// +j -j
dp
[
1
]
=
cs
[
0
];
dp
[
3
]
=
-
cs
[
1
];
dp
[
9
]
=
cs
[
2
];
dp
[
11
]
=
-
cs
[
3
];
dp
[
17
]
=
cs
[
4
];
dp
[
19
]
=
-
cs
[
5
];
dp
[
0
]
=
-
cs
[
0
];
dp
[
2
]
=
cs
[
1
];
dp
[
8
]
=
-
cs
[
2
];
dp
[
10
]
=
cs
[
3
];
dp
[
16
]
=
-
cs
[
4
];
dp
[
18
]
=
cs
[
5
];
break
;
default:
AssertFatal
(
1
==
0
,
"phich_coding.c: Illegal PHICH Number
\n
"
);
}
}
HI16
=
0
;
//#ifdef DEBUG_PHICH
//#endif
/*
for (i=0;i<200;i++)
printf("re %d: %d %d\n",i,((int16_t*)&rxdataF_comp[0][i])[0],((int16_t*)&rxdataF_comp[0][i])[1]);
*/
for
(
phich_quad
=
0
;
phich_quad
<
3
;
phich_quad
++
)
{
if
(
frame_parms
->
Ncp
==
1
)
reg_offset
=
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
phich_quad
]
*
4
)
+
(
phich_quad
*
frame_parms
->
N_RB_DL
*
12
);
else
reg_offset
=
(
frame_parms
->
phich_reg
[
ngroup_PHICH
][
phich_quad
]
*
4
);
// msg("\n[PUSCH 0]PHICH (RX) quad %d (%d)=>",phich_quad,reg_offset);
dp
=
&
d
[
phich_quad
*
8
];;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
phich_d_ptr
[
i
]
=
((
int16_t
*
)
&
rxdataF_comp
[
0
][
reg_offset
])[
i
];
#ifdef DEBUG_PHICH
LOG_D
(
PHY
,
"%d,"
,((
int16_t
*
)
&
rxdataF_comp
[
0
][
reg_offset
])[
i
]);
#endif
HI16
+=
(
phich_d_ptr
[
i
]
*
dp
[
i
]);
}
}
#ifdef DEBUG_PHICH
LOG_D
(
PHY
,
"
\n
"
);
LOG_D
(
PHY
,
"HI16 %d
\n
"
,
HI16
);
#endif
if
(
HI16
>
0
)
{
//NACK
if
(
ue
->
ulsch_Msg3_active
[
eNB_id
]
==
1
)
{
LOG_D
(
PHY
,
"[UE %d][PUSCH %d][RAPROC] Frame %d subframe %d Msg3 PHICH, received NAK (%d) nseq %d, ngroup %d
\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
,
subframe
,
HI16
,
nseq_PHICH
,
ngroup_PHICH
);
ulsch
->
f_pusch
+=
delta_PUSCH_acc
[
ulsch
->
harq_processes
[
harq_pid
]
->
TPC
];
LOG_D
(
PHY
,
"[PUSCH %d] AbsSubframe %d.%d: f_pusch (ACC) %d, adjusting by %d (TPC %d)
\n
"
,
harq_pid
,
proc
->
frame_rx
,
subframe
,
ulsch
->
f_pusch
,
delta_PUSCH_acc
[
ulsch
->
harq_processes
[
harq_pid
]
->
TPC
],
ulsch
->
harq_processes
[
harq_pid
]
->
TPC
);
ulsch
->
harq_processes
[
harq_pid
]
->
subframe_scheduling_flag
=
1
;
// ulsch->harq_processes[harq_pid]->Ndi = 0;
ulsch
->
harq_processes
[
harq_pid
]
->
round
++
;
ulsch
->
harq_processes
[
harq_pid
]
->
rvidx
=
rv_table
[
ulsch
->
harq_processes
[
harq_pid
]
->
round
&
3
];
if
(
ulsch
->
harq_processes
[
harq_pid
]
->
round
>=
ue
->
frame_parms
.
maxHARQ_Msg3Tx
)
{
ulsch
->
harq_processes
[
harq_pid
]
->
subframe_scheduling_flag
=
0
;
ulsch
->
harq_processes
[
harq_pid
]
->
status
=
SCH_IDLE
;
// inform MAC that Msg3 transmission has failed
ue
->
ulsch_Msg3_active
[
eNB_id
]
=
0
;
}
}
else
{
#ifdef UE_DEBUG_TRACE
LOG_D
(
PHY
,
"[UE %d][PUSCH %d] Frame %d subframe %d PHICH, received NAK (%d) nseq %d, ngroup %d round %d (Mlimit %d)
\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
%
1024
,
subframe
,
HI16
,
nseq_PHICH
,
ngroup_PHICH
,
ulsch
->
harq_processes
[
harq_pid
]
->
round
,
ulsch
->
Mlimit
);
#endif
// ulsch->harq_processes[harq_pid]->Ndi = 0;
ulsch
->
harq_processes
[
harq_pid
]
->
round
++
;
if
(
ulsch
->
harq_processes
[
harq_pid
]
->
round
>=
(
ulsch
->
Mlimit
-
1
)
)
{
// this is last push re transmission
ulsch
->
harq_processes
[
harq_pid
]
->
rvidx
=
rv_table
[
ulsch
->
harq_processes
[
harq_pid
]
->
round
&
3
];
ulsch
->
O_RI
=
0
;
ulsch
->
O
=
0
;
ulsch
->
uci_format
=
HLC_subband_cqi_nopmi
;
// disable phich decoding since it is the last retransmission
ulsch
->
harq_processes
[
harq_pid
]
->
status
=
SCH_IDLE
;
//ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0;
//ulsch->harq_processes[harq_pid]->round = 0;
//LOG_I(PHY,"PUSCH MAX Retransmission acheived ==> flush harq buff (%d) \n",harq_pid);
//LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->Mlimit, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round);
}
else
{
// ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1;
ulsch
->
harq_processes
[
harq_pid
]
->
rvidx
=
rv_table
[
ulsch
->
harq_processes
[
harq_pid
]
->
round
&
3
];
ulsch
->
O_RI
=
0
;
ulsch
->
O
=
0
;
ulsch
->
uci_format
=
HLC_subband_cqi_nopmi
;
//LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH NACK ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag,ulsch->harq_processes[harq_pid]->round);
}
}
#if T_TRACER
T
(
T_UE_PHY_ULSCH_UE_NACK
,
T_INT
(
eNB_id
),
T_INT
(
proc
->
frame_rx
%
1024
),
T_INT
(
subframe
),
T_INT
(
ulsch
->
rnti
),
T_INT
(
harq_pid
));
#endif
}
else
{
//ACK
if
(
ue
->
ulsch_Msg3_active
[
eNB_id
]
==
1
)
{
LOG_D
(
PHY
,
"[UE %d][PUSCH %d][RAPROC] Frame %d subframe %d Msg3 PHICH, received ACK (%d) nseq %d, ngroup %d
\n\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
,
subframe
,
HI16
,
nseq_PHICH
,
ngroup_PHICH
);
}
else
{
#ifdef UE_DEBUG_TRACE
LOG_D
(
PHY
,
"[UE %d][PUSCH %d] Frame %d subframe %d PHICH, received ACK (%d) nseq %d, ngroup %d
\n\n
"
,
ue
->
Mod_id
,
harq_pid
,
proc
->
frame_rx
%
1024
,
subframe
,
HI16
,
nseq_PHICH
,
ngroup_PHICH
);
#endif
}
// LOG_I(PHY,"[HARQ-UL harqId: %d] subframe_scheduling_flag = %d \n",harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag);
// Incase of adaptive retransmission, PHICH is always decoded as ACK (at least with OAI-eNB)
// Workaround:
// rely only on DCI0 decoding and check if NDI has toggled
// save current harq_processes content in temporary struct
// harqId-8 corresponds to the temporary struct. In total we have 8 harq process(0 ..7) + 1 temporary harq process()
//ulsch->harq_processes[8] = ulsch->harq_processes[harq_pid];
ulsch
->
harq_processes
[
harq_pid
]
->
status
=
SCH_IDLE
;
ulsch
->
harq_processes
[
harq_pid
]
->
round
=
0
;
ulsch
->
harq_processes
[
harq_pid
]
->
subframe_scheduling_flag
=
0
;
// inform MAC?
ue
->
ulsch_Msg3_active
[
eNB_id
]
=
0
;
#if T_TRACER
T
(
T_UE_PHY_ULSCH_UE_ACK
,
T_INT
(
eNB_id
),
T_INT
(
proc
->
frame_rx
%
1024
),
T_INT
(
subframe
),
T_INT
(
ulsch
->
rnti
),
T_INT
(
harq_pid
));
#endif
}
}
void
generate_phich_top
(
PHY_VARS_eNB
*
eNB
,
eNB_rxtx_proc_t
*
proc
,
int16_t
amp
)
{
LTE_DL_FRAME_PARMS
*
frame_parms
=&
eNB
->
frame_parms
;
int32_t
**
txdataF
=
eNB
->
common_vars
.
txdataF
;
uint8_t
harq_pid
;
uint8_t
Ngroup_PHICH
,
ngroup_PHICH
,
nseq_PHICH
;
uint8_t
NSF_PHICH
=
4
;
uint8_t
pusch_subframe
;
uint8_t
i
;
uint32_t
pusch_frame
;
int
subframe
=
proc
->
subframe_tx
;
phich_config_t
*
phich
;
// compute Ngroup_PHICH (see formula at beginning of Section 6.9 in 36-211
Ngroup_PHICH
=
(
frame_parms
->
phich_config_common
.
phich_resource
*
frame_parms
->
N_RB_DL
)
/
48
;
if
(((
frame_parms
->
phich_config_common
.
phich_resource
*
frame_parms
->
N_RB_DL
)
%
48
)
>
0
)
Ngroup_PHICH
++
;
if
(
frame_parms
->
Ncp
==
1
)
NSF_PHICH
=
2
;
if
(
eNB
->
phich_vars
[
subframe
&
1
].
num_hi
>
0
)
{
pusch_frame
=
phich_frame2_pusch_frame
(
frame_parms
,
proc
->
frame_tx
,
subframe
);
pusch_subframe
=
phich_subframe2_pusch_subframe
(
frame_parms
,
subframe
);
harq_pid
=
subframe2harq_pid
(
frame_parms
,
pusch_frame
,
pusch_subframe
);
}
for
(
i
=
0
;
i
<
eNB
->
phich_vars
[
subframe
&
1
].
num_hi
;
i
++
)
{
phich
=
&
eNB
->
phich_vars
[
subframe
&
1
].
config
[
i
];
ngroup_PHICH
=
(
phich
->
first_rb
+
phich
->
n_DMRS
)
%
Ngroup_PHICH
;
if
((
frame_parms
->
tdd_config
==
0
)
&&
(
frame_parms
->
frame_type
==
TDD
)
)
{
if
((
pusch_subframe
==
4
)
||
(
pusch_subframe
==
9
))
ngroup_PHICH
+=
Ngroup_PHICH
;
}
nseq_PHICH
=
((
phich
->
first_rb
/
Ngroup_PHICH
)
+
phich
->
n_DMRS
)
%
(
2
*
NSF_PHICH
);
LOG_D
(
PHY
,
"[eNB %d][PUSCH %d] Frame %d subframe %d Generating PHICH, AMP %d ngroup_PHICH %d/%d, nseq_PHICH %d : HI %d, first_rb %d)
\n
"
,
eNB
->
Mod_id
,
harq_pid
,
proc
->
frame_tx
,
subframe
,
amp
,
ngroup_PHICH
,
Ngroup_PHICH
,
nseq_PHICH
,
phich
->
hi
,
phich
->
first_rb
);
T
(
T_ENB_PHY_PHICH
,
T_INT
(
eNB
->
Mod_id
),
T_INT
(
proc
->
frame_tx
),
T_INT
(
subframe
),
T_INT
(
-
1
/* TODO: rnti */
),
T_INT
(
harq_pid
),
T_INT
(
Ngroup_PHICH
),
T_INT
(
NSF_PHICH
),
T_INT
(
ngroup_PHICH
),
T_INT
(
nseq_PHICH
),
T_INT
(
phich
->
hi
),
T_INT
(
phich
->
first_rb
),
T_INT
(
phich
->
n_DMRS
));
generate_phich
(
frame_parms
,
amp
,
//amp*2,
nseq_PHICH
,
ngroup_PHICH
,
phich
->
hi
,
subframe
,
txdataF
);
}
// for (i=0; i<eNB->phich_vars[subframe&1].num_hi; i++) {
eNB
->
phich_vars
[
subframe
&
1
].
num_hi
=
0
;
}
openair1/PHY/LTE_UE_TRANSPORT/pmch_ue.c
0 → 100644
View file @
fe95f0f4
/*
* 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
*/
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "PHY/sse_intrin.h"
// Mask for identifying subframe for MBMS
#define MBSFN_TDD_SF3 0x80// for TDD
#define MBSFN_TDD_SF4 0x40
#define MBSFN_TDD_SF7 0x20
#define MBSFN_TDD_SF8 0x10
#define MBSFN_TDD_SF9 0x08
#include "PHY/defs.h"
#define MBSFN_FDD_SF1 0x80// for FDD
#define MBSFN_FDD_SF2 0x40
#define MBSFN_FDD_SF3 0x20
#define MBSFN_FDD_SF6 0x10
#define MBSFN_FDD_SF7 0x08
#define MBSFN_FDD_SF8 0x04
void
dump_mch
(
PHY_VARS_UE
*
ue
,
uint8_t
eNB_id
,
uint16_t
coded_bits_per_codeword
,
int
subframe
)
{
unsigned
int
nsymb_pmch
=
12
;
char
fname
[
32
],
vname
[
32
];
int
N_RB_DL
=
ue
->
frame_parms
.
N_RB_DL
;
sprintf
(
fname
,
"mch_rxF_ext0.m"
);
sprintf
(
vname
,
"pmch_rxF_ext0"
);
write_output
(
fname
,
vname
,
ue
->
pdsch_vars_MCH
[
eNB_id
]
->
rxdataF_ext
[
0
],
12
*
N_RB_DL
*
nsymb_pmch
,
1
,
1
);
sprintf
(
fname
,
"mch_ch_ext00.m"
);
sprintf
(
vname
,
"pmch_ch_ext00"
);
write_output
(
fname
,
vname
,
ue
->
pdsch_vars_MCH
[
eNB_id
]
->
dl_ch_estimates_ext
[
0
],
12
*
N_RB_DL
*
nsymb_pmch
,
1
,
1
);
/*
write_output("dlsch%d_ch_ext01.m","dl01_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[1],12*N_RB_DL*nsymb_pmch,1,1);
write_output("dlsch%d_ch_ext10.m","dl10_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[2],12*N_RB_DL*nsymb_pmch,1,1);
write_output("dlsch%d_ch_ext11.m","dl11_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[3],12*N_RB_DL*nsymb_pmch,1,1);
write_output("dlsch%d_rho.m","dl_rho",pdsch_vars[eNB_id]->rho[0],12*N_RB_DL*nsymb_pmch,1,1);
*/
sprintf
(
fname
,
"mch_rxF_comp0.m"
);
sprintf
(
vname
,
"pmch_rxF_comp0"
);
write_output
(
fname
,
vname
,
ue
->
pdsch_vars_MCH
[
eNB_id
]
->
rxdataF_comp0
[
0
],
12
*
N_RB_DL
*
nsymb_pmch
,
1
,
1
);
sprintf
(
fname
,
"mch_rxF_llr.m"
);
sprintf
(
vname
,
"pmch_llr"
);
write_output
(
fname
,
vname
,
ue
->
pdsch_vars_MCH
[
eNB_id
]
->
llr
[
0
],
coded_bits_per_codeword
,
1
,
0
);
sprintf
(
fname
,
"mch_mag1.m"
);
sprintf
(
vname
,
"pmch_mag1"
);
write_output
(
fname
,
vname
,
ue
->
pdsch_vars_MCH
[
eNB_id
]
->
dl_ch_mag0
[
0
],
12
*
N_RB_DL
*
nsymb_pmch
,
1
,
1
);
sprintf
(
fname
,
"mch_mag2.m"
);
sprintf
(
vname
,
"pmch_mag2"
);
write_output
(
fname
,
vname
,
ue
->
pdsch_vars_MCH
[
eNB_id
]
->
dl_ch_magb0
[
0
],
12
*
N_RB_DL
*
nsymb_pmch
,
1
,
1
);
write_output
(
"mch00_ch0.m"
,
"pmch00_ch0"
,
&
(
ue
->
common_vars
.
common_vars_rx_data_per_thread
[
ue
->
current_thread_id
[
subframe
]].
dl_ch_estimates
[
eNB_id
][
0
][
0
]),
ue
->
frame_parms
.
ofdm_symbol_size
*
12
,
1
,
1
);
write_output
(
"rxsig_mch.m"
,
"rxs_mch"
,
&
ue
->
common_vars
.
rxdata
[
0
][
subframe
*
ue
->
frame_parms
.
samples_per_tti
],
ue
->
frame_parms
.
samples_per_tti
,
1
,
1
);
/*
if (PHY_vars_eNB_g)
write_output("txsig_mch.m","txs_mch",
&PHY_vars_eNB_g[0][0]->common_vars.txdata[0][0][subframe*ue->frame_parms.samples_per_tti],
ue->frame_parms.samples_per_tti,1,1);*/
}
int
is_pmch_subframe
(
uint32_t
frame
,
int
subframe
,
LTE_DL_FRAME_PARMS
*
frame_parms
)
{
uint32_t
period
;
uint8_t
i
;
// LOG_D(PHY,"is_pmch_subframe: frame %d, subframe %d, num_MBSFN_config %d\n",
// frame,subframe,frame_parms->num_MBSFN_config);
for
(
i
=
0
;
i
<
frame_parms
->
num_MBSFN_config
;
i
++
)
{
// we have at least one MBSFN configuration
period
=
1
<<
frame_parms
->
MBSFN_config
[
i
].
radioframeAllocationPeriod
;
if
((
frame
%
period
)
==
frame_parms
->
MBSFN_config
[
i
].
radioframeAllocationOffset
)
{
if
(
frame_parms
->
MBSFN_config
[
i
].
fourFrames_flag
==
0
)
{
if
(
frame_parms
->
frame_type
==
FDD
)
{
switch
(
subframe
)
{
case
1
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_FDD_SF1
)
>
0
)
return
(
1
);
break
;
case
2
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_FDD_SF2
)
>
0
)
return
(
1
);
break
;
case
3
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_FDD_SF3
)
>
0
)
return
(
1
);
break
;
case
6
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_FDD_SF6
)
>
0
)
return
(
1
);
break
;
case
7
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_FDD_SF7
)
>
0
)
return
(
1
);
break
;
case
8
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_FDD_SF8
)
>
0
)
return
(
1
);
break
;
}
}
else
{
switch
(
subframe
)
{
case
3
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_TDD_SF3
)
>
0
)
return
(
1
);
break
;
case
4
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_TDD_SF4
)
>
0
)
return
(
1
);
break
;
case
7
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_TDD_SF7
)
>
0
)
return
(
1
);
break
;
case
8
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_TDD_SF8
)
>
0
)
return
(
1
);
break
;
case
9
:
if
((
frame_parms
->
MBSFN_config
[
i
].
mbsfn_SubframeConfig
&
MBSFN_TDD_SF9
)
>
0
)
return
(
1
);
break
;
}
}
}
else
{
// handle 4 frames case
}
}
}
return
(
0
);
}
void
fill_eNB_dlsch_MCH
(
PHY_VARS_eNB
*
eNB
,
int
mcs
,
int
ndi
,
int
rvidx
)
{
LTE_eNB_DLSCH_t
*
dlsch
=
eNB
->
dlsch_MCH
;
LTE_DL_FRAME_PARMS
*
frame_parms
=&
eNB
->
frame_parms
;
// dlsch->rnti = M_RNTI;
dlsch
->
harq_processes
[
0
]
->
mcs
=
mcs
;
// dlsch->harq_processes[0]->Ndi = ndi;
dlsch
->
harq_processes
[
0
]
->
rvidx
=
rvidx
;
dlsch
->
harq_processes
[
0
]
->
Nl
=
1
;
dlsch
->
harq_processes
[
0
]
->
TBS
=
TBStable
[
get_I_TBS
(
dlsch
->
harq_processes
[
0
]
->
mcs
)][
frame_parms
->
N_RB_DL
-
1
];
// dlsch->harq_ids[subframe] = 0;
dlsch
->
harq_processes
[
0
]
->
nb_rb
=
frame_parms
->
N_RB_DL
;
switch
(
frame_parms
->
N_RB_DL
)
{
case
6
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
0
]
=
0x3f
;
break
;
case
25
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
0
]
=
0x1ffffff
;
break
;
case
50
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
0
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
1
]
=
0x3ffff
;
break
;
case
100
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
0
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
1
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
2
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc
[
3
]
=
0xf
;
break
;
}
if
(
eNB
->
abstraction_flag
)
{
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
cntl
.
pmch_flag
=
1
;
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
num_pmch
=
1
;
// assumption: there is always one pmch in each SF
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
num_common_dci
=
0
;
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
num_ue_spec_dci
=
0
;
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
dlsch_type
[
0
]
=
5
;
// put at the reserved position for PMCH
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
harq_pid
[
0
]
=
0
;
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
ue_id
[
0
]
=
255
;
//broadcast
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
tbs
[
0
]
=
dlsch
->
harq_processes
[
0
]
->
TBS
>>
3
;
}
}
void
fill_UE_dlsch_MCH
(
PHY_VARS_UE
*
ue
,
int
mcs
,
int
ndi
,
int
rvidx
,
int
eNB_id
)
{
LTE_UE_DLSCH_t
*
dlsch
=
ue
->
dlsch_MCH
[
eNB_id
];
LTE_DL_FRAME_PARMS
*
frame_parms
=&
ue
->
frame_parms
;
// dlsch->rnti = M_RNTI;
dlsch
->
harq_processes
[
0
]
->
mcs
=
mcs
;
dlsch
->
harq_processes
[
0
]
->
rvidx
=
rvidx
;
// dlsch->harq_processes[0]->Ndi = ndi;
dlsch
->
harq_processes
[
0
]
->
Nl
=
1
;
dlsch
->
harq_processes
[
0
]
->
TBS
=
TBStable
[
get_I_TBS
(
dlsch
->
harq_processes
[
0
]
->
mcs
)][
frame_parms
->
N_RB_DL
-
1
];
dlsch
->
current_harq_pid
=
0
;
dlsch
->
harq_processes
[
0
]
->
nb_rb
=
frame_parms
->
N_RB_DL
;
switch
(
frame_parms
->
N_RB_DL
)
{
case
6
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
0
]
=
0x3f
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
0
]
=
0x3f
;
break
;
case
25
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
0
]
=
0x1ffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
0
]
=
0x1ffffff
;
break
;
case
50
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
0
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
0
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
1
]
=
0x3ffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
1
]
=
0x3ffff
;
break
;
case
100
:
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
0
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
0
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
1
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
1
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
2
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
2
]
=
0xffffffff
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_even
[
3
]
=
0xf
;
dlsch
->
harq_processes
[
0
]
->
rb_alloc_odd
[
3
]
=
0xf
;
break
;
}
}
void
generate_mch
(
PHY_VARS_eNB
*
eNB
,
eNB_rxtx_proc_t
*
proc
,
uint8_t
*
a
)
{
int
G
;
int
subframe
=
proc
->
subframe_tx
;
int
frame
=
proc
->
frame_tx
;
if
(
eNB
->
abstraction_flag
!=
0
)
{
if
(
eNB_transport_info_TB_index
[
eNB
->
Mod_id
][
eNB
->
CC_id
]
!=
0
)
printf
(
"[PHY][EMU] PMCH transport block position is different than zero %d
\n
"
,
eNB_transport_info_TB_index
[
eNB
->
Mod_id
][
eNB
->
CC_id
]);
memcpy
(
eNB
->
dlsch_MCH
->
harq_processes
[
0
]
->
b
,
a
,
eNB
->
dlsch_MCH
->
harq_processes
[
0
]
->
TBS
>>
3
);
LOG_D
(
PHY
,
"[eNB %d] dlsch_encoding_emul pmch , tbs is %d
\n
"
,
eNB
->
Mod_id
,
eNB
->
dlsch_MCH
->
harq_processes
[
0
]
->
TBS
>>
3
);
memcpy
(
&
eNB_transport_info
[
eNB
->
Mod_id
][
eNB
->
CC_id
].
transport_blocks
[
eNB_transport_info_TB_index
[
eNB
->
Mod_id
][
eNB
->
CC_id
]],
a
,
eNB
->
dlsch_MCH
->
harq_processes
[
0
]
->
TBS
>>
3
);
eNB_transport_info_TB_index
[
eNB
->
Mod_id
][
eNB
->
CC_id
]
+=
eNB
->
dlsch_MCH
->
harq_processes
[
0
]
->
TBS
>>
3
;
//=eNB_transport_info[eNB->Mod_id].tbs[0];
}
else
{
G
=
get_G
(
&
eNB
->
frame_parms
,
eNB
->
frame_parms
.
N_RB_DL
,
eNB
->
dlsch_MCH
->
harq_processes
[
0
]
->
rb_alloc
,
get_Qm
(
eNB
->
dlsch_MCH
->
harq_processes
[
0
]
->
mcs
),
1
,
2
,
proc
->
frame_tx
,
subframe
,
0
);
generate_mbsfn_pilot
(
eNB
,
proc
,
eNB
->
common_vars
.
txdataF
,
AMP
);
AssertFatal
(
dlsch_encoding
(
eNB
,
a
,
1
,
eNB
->
dlsch_MCH
,
proc
->
frame_tx
,
subframe
,
&
eNB
->
dlsch_rate_matching_stats
,
&
eNB
->
dlsch_turbo_encoding_stats
,
&
eNB
->
dlsch_interleaving_stats
)
==
0
,
"problem in dlsch_encoding"
);
dlsch_scrambling
(
&
eNB
->
frame_parms
,
1
,
eNB
->
dlsch_MCH
,
0
,
G
,
0
,
frame
,
subframe
<<
1
);
mch_modulation
(
eNB
->
common_vars
.
txdataF
,
AMP
,
subframe
,
&
eNB
->
frame_parms
,
eNB
->
dlsch_MCH
);
}
}
void
mch_extract_rbs
(
int
**
rxdataF
,
int
**
dl_ch_estimates
,
int
**
rxdataF_ext
,
int
**
dl_ch_estimates_ext
,
unsigned
char
symbol
,
unsigned
char
subframe
,
LTE_DL_FRAME_PARMS
*
frame_parms
)
{
int
pilots
=
0
,
i
,
j
,
offset
,
aarx
;
// printf("Extracting PMCH: symbol %d\n",symbol);
if
((
symbol
==
2
)
||
(
symbol
==
10
))
{
pilots
=
1
;
offset
=
1
;
}
else
if
(
symbol
==
6
)
{
pilots
=
1
;
offset
=
0
;
}
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
{
if
(
pilots
==
1
)
{
for
(
i
=
offset
,
j
=
0
;
i
<
frame_parms
->
N_RB_DL
*
6
;
i
+=
2
,
j
++
)
{
/* printf("MCH with pilots: i %d, j %d => %d,%d\n",i,j,
*(int16_t*)&rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)],
*(int16_t*)(1+&rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)]));
*/
rxdataF_ext
[
aarx
][
j
+
symbol
*
(
frame_parms
->
N_RB_DL
*
12
)]
=
rxdataF
[
aarx
][
i
+
frame_parms
->
first_carrier_offset
+
(
symbol
*
frame_parms
->
ofdm_symbol_size
)];
rxdataF_ext
[
aarx
][(
frame_parms
->
N_RB_DL
*
3
)
+
j
+
symbol
*
(
frame_parms
->
N_RB_DL
*
12
)]
=
rxdataF
[
aarx
][
i
+
1
+
(
symbol
*
frame_parms
->
ofdm_symbol_size
)];
dl_ch_estimates_ext
[
aarx
][
j
+
symbol
*
(
frame_parms
->
N_RB_DL
*
12
)]
=
dl_ch_estimates
[
aarx
][
i
+
(
symbol
*
frame_parms
->
ofdm_symbol_size
)];
dl_ch_estimates_ext
[
aarx
][(
frame_parms
->
N_RB_DL
*
3
)
+
j
+
symbol
*
(
frame_parms
->
N_RB_DL
*
12
)]
=
dl_ch_estimates
[
aarx
][
i
+
(
frame_parms
->
N_RB_DL
*
6
)
+
(
symbol
*
frame_parms
->
ofdm_symbol_size
)];
}
}
else
{
memcpy
((
void
*
)
&
rxdataF_ext
[
aarx
][
symbol
*
(
frame_parms
->
N_RB_DL
*
12
)],
(
void
*
)
&
rxdataF
[
aarx
][
frame_parms
->
first_carrier_offset
+
(
symbol
*
frame_parms
->
ofdm_symbol_size
)],
frame_parms
->
N_RB_DL
*
24
);
memcpy
((
void
*
)
&
rxdataF_ext
[
aarx
][(
frame_parms
->
N_RB_DL
*
6
)
+
symbol
*
(
frame_parms
->
N_RB_DL
*
12
)],
(
void
*
)
&
rxdataF
[
aarx
][
1
+
(
symbol
*
frame_parms
->
ofdm_symbol_size
)],
frame_parms
->
N_RB_DL
*
24
);
memcpy
((
void
*
)
&
dl_ch_estimates_ext
[
aarx
][
symbol
*
(
frame_parms
->
N_RB_DL
*
12
)],
(
void
*
)
&
dl_ch_estimates
[
aarx
][(
symbol
*
frame_parms
->
ofdm_symbol_size
)],
frame_parms
->
N_RB_DL
*
48
);
}
}
}
void
mch_channel_level
(
int
**
dl_ch_estimates_ext
,
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
*
avg
,
uint8_t
symbol
,
unsigned
short
nb_rb
)
{
int
i
,
aarx
,
nre
;
#if defined(__x86_64__) || defined(__i386__)
__m128i
*
dl_ch128
,
avg128
;
#elif defined(__arm__)
int32x4_t
avg128
;
#endif
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
{
#if defined(__x86_64__) || defined(__i386__)
//clear average level
avg128
=
_mm_setzero_si128
();
// 5 is always a symbol with no pilots for both normal and extended prefix
dl_ch128
=
(
__m128i
*
)
&
dl_ch_estimates_ext
[
aarx
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
#elif defined(__arm__)
#endif
if
((
symbol
==
2
)
||
(
symbol
==
6
)
||
(
symbol
==
10
))
nre
=
(
frame_parms
->
N_RB_DL
*
6
);
else
nre
=
(
frame_parms
->
N_RB_DL
*
12
);
for
(
i
=
0
;
i
<
(
nre
>>
2
);
i
++
)
{
#if defined(__x86_64__) || defined(__i386__)
avg128
=
_mm_add_epi32
(
avg128
,
_mm_madd_epi16
(
dl_ch128
[
0
],
dl_ch128
[
0
]));
#elif defined(__arm__)
#endif
}
avg
[
aarx
]
=
(((
int
*
)
&
avg128
)[
0
]
+
((
int
*
)
&
avg128
)[
1
]
+
((
int
*
)
&
avg128
)[
2
]
+
((
int
*
)
&
avg128
)[
3
])
/
nre
;
// printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
}
void
mch_channel_compensation
(
int
**
rxdataF_ext
,
int
**
dl_ch_estimates_ext
,
int
**
dl_ch_mag
,
int
**
dl_ch_magb
,
int
**
rxdataF_comp
,
LTE_DL_FRAME_PARMS
*
frame_parms
,
unsigned
char
symbol
,
unsigned
char
mod_order
,
unsigned
char
output_shift
)
{
int
aarx
,
nre
,
i
;
#if defined(__x86_64__) || defined(__i386__)
__m128i
*
dl_ch128
,
*
dl_ch_mag128
,
*
dl_ch_mag128b
,
*
rxdataF128
,
*
rxdataF_comp128
;
__m128i
mmtmpD0
,
mmtmpD1
,
mmtmpD2
,
mmtmpD3
,
QAM_amp128
,
QAM_amp128b
;
#elif defined(__arm__)
#endif
if
((
symbol
==
2
)
||
(
symbol
==
6
)
||
(
symbol
==
10
))
nre
=
frame_parms
->
N_RB_DL
*
6
;
else
nre
=
frame_parms
->
N_RB_DL
*
12
;
#if defined(__x86_64__) || defined(__i386__)
if
(
mod_order
==
4
)
{
QAM_amp128
=
_mm_set1_epi16
(
QAM16_n1
);
// 2/sqrt(10)
QAM_amp128b
=
_mm_setzero_si128
();
}
else
if
(
mod_order
==
6
)
{
QAM_amp128
=
_mm_set1_epi16
(
QAM64_n1
);
//
QAM_amp128b
=
_mm_set1_epi16
(
QAM64_n2
);
}
#elif defined(__arm__)
#endif
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
{
#if defined(__x86_64__) || defined(__i386__)
dl_ch128
=
(
__m128i
*
)
&
dl_ch_estimates_ext
[
aarx
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128
=
(
__m128i
*
)
&
dl_ch_mag
[
aarx
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128b
=
(
__m128i
*
)
&
dl_ch_magb
[
aarx
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
rxdataF128
=
(
__m128i
*
)
&
rxdataF_ext
[
aarx
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
rxdataF_comp128
=
(
__m128i
*
)
&
rxdataF_comp
[
aarx
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
#elif defined(__arm__)
#endif
for
(
i
=
0
;
i
<
(
nre
>>
2
);
i
+=
2
)
{
if
(
mod_order
>
2
)
{
// get channel amplitude if not QPSK
#if defined(__x86_64__) || defined(__i386__)
mmtmpD0
=
_mm_madd_epi16
(
dl_ch128
[
0
],
dl_ch128
[
0
]);
mmtmpD0
=
_mm_srai_epi32
(
mmtmpD0
,
output_shift
);
mmtmpD1
=
_mm_madd_epi16
(
dl_ch128
[
1
],
dl_ch128
[
1
]);
mmtmpD1
=
_mm_srai_epi32
(
mmtmpD1
,
output_shift
);
mmtmpD0
=
_mm_packs_epi32
(
mmtmpD0
,
mmtmpD1
);
// store channel magnitude here in a new field of dlsch
dl_ch_mag128
[
0
]
=
_mm_unpacklo_epi16
(
mmtmpD0
,
mmtmpD0
);
dl_ch_mag128b
[
0
]
=
dl_ch_mag128
[
0
];
dl_ch_mag128
[
0
]
=
_mm_mulhi_epi16
(
dl_ch_mag128
[
0
],
QAM_amp128
);
dl_ch_mag128
[
0
]
=
_mm_slli_epi16
(
dl_ch_mag128
[
0
],
1
);
dl_ch_mag128
[
1
]
=
_mm_unpackhi_epi16
(
mmtmpD0
,
mmtmpD0
);
dl_ch_mag128b
[
1
]
=
dl_ch_mag128
[
1
];
dl_ch_mag128
[
1
]
=
_mm_mulhi_epi16
(
dl_ch_mag128
[
1
],
QAM_amp128
);
dl_ch_mag128
[
1
]
=
_mm_slli_epi16
(
dl_ch_mag128
[
1
],
1
);
dl_ch_mag128b
[
0
]
=
_mm_mulhi_epi16
(
dl_ch_mag128b
[
0
],
QAM_amp128b
);
dl_ch_mag128b
[
0
]
=
_mm_slli_epi16
(
dl_ch_mag128b
[
0
],
1
);
dl_ch_mag128b
[
1
]
=
_mm_mulhi_epi16
(
dl_ch_mag128b
[
1
],
QAM_amp128b
);
dl_ch_mag128b
[
1
]
=
_mm_slli_epi16
(
dl_ch_mag128b
[
1
],
1
);
#elif defined(__arm__)
#endif
}
#if defined(__x86_64__) || defined(__i386__)
// multiply by conjugated channel
mmtmpD0
=
_mm_madd_epi16
(
dl_ch128
[
0
],
rxdataF128
[
0
]);
// print_ints("re",&mmtmpD0);
// mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
mmtmpD1
=
_mm_shufflelo_epi16
(
dl_ch128
[
0
],
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpD1
=
_mm_shufflehi_epi16
(
mmtmpD1
,
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpD1
=
_mm_sign_epi16
(
mmtmpD1
,
*
(
__m128i
*
)
&
conjugate
[
0
]);
// print_ints("im",&mmtmpD1);
mmtmpD1
=
_mm_madd_epi16
(
mmtmpD1
,
rxdataF128
[
0
]);
// mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpD0
=
_mm_srai_epi32
(
mmtmpD0
,
output_shift
);
// print_ints("re(shift)",&mmtmpD0);
mmtmpD1
=
_mm_srai_epi32
(
mmtmpD1
,
output_shift
);
// print_ints("im(shift)",&mmtmpD1);
mmtmpD2
=
_mm_unpacklo_epi32
(
mmtmpD0
,
mmtmpD1
);
mmtmpD3
=
_mm_unpackhi_epi32
(
mmtmpD0
,
mmtmpD1
);
// print_ints("c0",&mmtmpD2);
// print_ints("c1",&mmtmpD3);
rxdataF_comp128
[
0
]
=
_mm_packs_epi32
(
mmtmpD2
,
mmtmpD3
);
// print_shorts("rx:",rxdataF128);
// print_shorts("ch:",dl_ch128);
// print_shorts("pack:",rxdataF_comp128);
// multiply by conjugated channel
mmtmpD0
=
_mm_madd_epi16
(
dl_ch128
[
1
],
rxdataF128
[
1
]);
// mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
mmtmpD1
=
_mm_shufflelo_epi16
(
dl_ch128
[
1
],
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpD1
=
_mm_shufflehi_epi16
(
mmtmpD1
,
_MM_SHUFFLE
(
2
,
3
,
0
,
1
));
mmtmpD1
=
_mm_sign_epi16
(
mmtmpD1
,
*
(
__m128i
*
)
conjugate
);
mmtmpD1
=
_mm_madd_epi16
(
mmtmpD1
,
rxdataF128
[
1
]);
// mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpD0
=
_mm_srai_epi32
(
mmtmpD0
,
output_shift
);
mmtmpD1
=
_mm_srai_epi32
(
mmtmpD1
,
output_shift
);
mmtmpD2
=
_mm_unpacklo_epi32
(
mmtmpD0
,
mmtmpD1
);
mmtmpD3
=
_mm_unpackhi_epi32
(
mmtmpD0
,
mmtmpD1
);
rxdataF_comp128
[
1
]
=
_mm_packs_epi32
(
mmtmpD2
,
mmtmpD3
);
// print_shorts("rx:",rxdataF128+1);
// print_shorts("ch:",dl_ch128+1);
// print_shorts("pack:",rxdataF_comp128+1);
dl_ch128
+=
2
;
dl_ch_mag128
+=
2
;
dl_ch_mag128b
+=
2
;
rxdataF128
+=
2
;
rxdataF_comp128
+=
2
;
#elif defined(__arm__)
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
}
void
mch_detection_mrc
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
**
rxdataF_comp
,
int
**
dl_ch_mag
,
int
**
dl_ch_magb
,
unsigned
char
symbol
)
{
int
i
;
#if defined(__x86_64__) || defined(__i386__)
__m128i
*
rxdataF_comp128_0
,
*
rxdataF_comp128_1
,
*
dl_ch_mag128_0
,
*
dl_ch_mag128_1
,
*
dl_ch_mag128_0b
,
*
dl_ch_mag128_1b
;
#elif defined(__arm__)
int16x8_t
*
rxdataF_comp128_0
,
*
rxdataF_comp128_1
,
*
dl_ch_mag128_0
,
*
dl_ch_mag128_1
,
*
dl_ch_mag128_0b
,
*
dl_ch_mag128_1b
;
#endif
if
(
frame_parms
->
nb_antennas_rx
>
1
)
{
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0
=
(
__m128i
*
)
&
rxdataF_comp
[
0
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
rxdataF_comp128_1
=
(
__m128i
*
)
&
rxdataF_comp
[
1
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_0
=
(
__m128i
*
)
&
dl_ch_mag
[
0
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_1
=
(
__m128i
*
)
&
dl_ch_mag
[
1
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_0b
=
(
__m128i
*
)
&
dl_ch_magb
[
0
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_1b
=
(
__m128i
*
)
&
dl_ch_magb
[
1
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
#elif defined(__arm__)
rxdataF_comp128_0
=
(
int16x8_t
*
)
&
rxdataF_comp
[
0
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
rxdataF_comp128_1
=
(
int16x8_t
*
)
&
rxdataF_comp
[
1
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_0
=
(
int16x8_t
*
)
&
dl_ch_mag
[
0
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_1
=
(
int16x8_t
*
)
&
dl_ch_mag
[
1
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_0b
=
(
int16x8_t
*
)
&
dl_ch_magb
[
0
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
dl_ch_mag128_1b
=
(
int16x8_t
*
)
&
dl_ch_magb
[
1
][
symbol
*
frame_parms
->
N_RB_DL
*
12
];
#endif
// MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
for
(
i
=
0
;
i
<
frame_parms
->
N_RB_DL
*
3
;
i
++
)
{
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0
[
i
]
=
_mm_adds_epi16
(
_mm_srai_epi16
(
rxdataF_comp128_0
[
i
],
1
),
_mm_srai_epi16
(
rxdataF_comp128_1
[
i
],
1
));
dl_ch_mag128_0
[
i
]
=
_mm_adds_epi16
(
_mm_srai_epi16
(
dl_ch_mag128_0
[
i
],
1
),
_mm_srai_epi16
(
dl_ch_mag128_1
[
i
],
1
));
dl_ch_mag128_0b
[
i
]
=
_mm_adds_epi16
(
_mm_srai_epi16
(
dl_ch_mag128_0b
[
i
],
1
),
_mm_srai_epi16
(
dl_ch_mag128_1b
[
i
],
1
));
#elif defined(__arm__)
rxdataF_comp128_0
[
i
]
=
vhaddq_s16
(
rxdataF_comp128_0
[
i
],
rxdataF_comp128_1
[
i
]);
dl_ch_mag128_0
[
i
]
=
vhaddq_s16
(
dl_ch_mag128_0
[
i
],
dl_ch_mag128_1
[
i
]);
dl_ch_mag128_0b
[
i
]
=
vhaddq_s16
(
dl_ch_mag128_0b
[
i
],
dl_ch_mag128_1b
[
i
]);
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
}
int
mch_qpsk_llr
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
**
rxdataF_comp
,
short
*
dlsch_llr
,
unsigned
char
symbol
,
short
**
llr32p
)
{
uint32_t
*
rxF
=
(
uint32_t
*
)
&
rxdataF_comp
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
uint32_t
*
llr32
;
int
i
,
len
;
if
(
symbol
==
2
)
{
llr32
=
(
uint32_t
*
)
dlsch_llr
;
}
else
{
llr32
=
(
uint32_t
*
)(
*
llr32p
);
}
AssertFatal
(
llr32
!=
NULL
,
"dlsch_qpsk_llr: llr is null, symbol %d, llr32=%p
\n
"
,
symbol
,
llr32
);
if
((
symbol
==
2
)
||
(
symbol
==
6
)
||
(
symbol
==
10
))
{
len
=
frame_parms
->
N_RB_DL
*
6
;
}
else
{
len
=
frame_parms
->
N_RB_DL
*
12
;
}
// printf("dlsch_qpsk_llr: symbol %d,len %d,pbch_pss_sss_adjust %d\n",symbol,len,pbch_pss_sss_adjust);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
*
llr32
=
*
rxF
;
rxF
++
;
llr32
++
;
}
*
llr32p
=
(
short
*
)
llr32
;
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
return
(
0
);
}
//----------------------------------------------------------------------------------------------
// 16-QAM
//----------------------------------------------------------------------------------------------
void
mch_16qam_llr
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
**
rxdataF_comp
,
short
*
dlsch_llr
,
int
**
dl_ch_mag
,
unsigned
char
symbol
,
int16_t
**
llr32p
)
{
#if defined(__x86_64__) || defined(__i386__)
__m128i
*
rxF
=
(
__m128i
*
)
&
rxdataF_comp
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
__m128i
*
ch_mag
;
__m128i
llr128
[
2
],
xmm0
;
uint32_t
*
llr32
;
#elif defined(__arm__)
int16x8_t
*
rxF
=
(
int16x8_t
*
)
&
rxdataF_comp
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
int16x8_t
*
ch_mag
;
int16x8_t
llr128
[
2
],
xmm0
;
int16_t
*
llr16
;
#endif
int
i
,
len
;
unsigned
char
len_mod4
=
0
;
#if defined(__x86_64__) || defined(__i386__)
if
(
symbol
==
2
)
{
llr32
=
(
uint32_t
*
)
dlsch_llr
;
}
else
{
llr32
=
(
uint32_t
*
)
*
llr32p
;
}
#elif defined(__arm__)
if
(
symbol
==
2
)
{
llr16
=
(
int16_t
*
)
dlsch_llr
;
}
else
{
llr16
=
(
int16_t
*
)
*
llr32p
;
}
#endif
#if defined(__x86_64__) || defined(__i386__)
ch_mag
=
(
__m128i
*
)
&
dl_ch_mag
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
#elif defined(__arm__)
ch_mag
=
(
int16x8_t
*
)
&
dl_ch_mag
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
#endif
if
((
symbol
==
2
)
||
(
symbol
==
6
)
||
(
symbol
==
10
))
{
len
=
frame_parms
->
N_RB_DL
*
6
;
}
else
{
len
=
frame_parms
->
N_RB_DL
*
12
;
}
// update output pointer according to number of REs in this symbol (<<2 because 4 bits per RE)
if
(
symbol
==
2
)
*
llr32p
=
dlsch_llr
+
(
len
<<
2
);
else
*
llr32p
+=
(
len
<<
2
);
len_mod4
=
len
&
3
;
len
>>=
2
;
// length in quad words (4 REs)
len
+=
(
len_mod4
==
0
?
0
:
1
);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
#if defined(__x86_64__) || defined(__i386__)
xmm0
=
_mm_abs_epi16
(
rxF
[
i
]);
xmm0
=
_mm_subs_epi16
(
ch_mag
[
i
],
xmm0
);
// lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
llr128
[
0
]
=
_mm_unpacklo_epi32
(
rxF
[
i
],
xmm0
);
llr128
[
1
]
=
_mm_unpackhi_epi32
(
rxF
[
i
],
xmm0
);
llr32
[
0
]
=
((
uint32_t
*
)
&
llr128
[
0
])[
0
];
llr32
[
1
]
=
((
uint32_t
*
)
&
llr128
[
0
])[
1
];
llr32
[
2
]
=
((
uint32_t
*
)
&
llr128
[
0
])[
2
];
llr32
[
3
]
=
((
uint32_t
*
)
&
llr128
[
0
])[
3
];
llr32
[
4
]
=
((
uint32_t
*
)
&
llr128
[
1
])[
0
];
llr32
[
5
]
=
((
uint32_t
*
)
&
llr128
[
1
])[
1
];
llr32
[
6
]
=
((
uint32_t
*
)
&
llr128
[
1
])[
2
];
llr32
[
7
]
=
((
uint32_t
*
)
&
llr128
[
1
])[
3
];
llr32
+=
8
;
#elif defined(__arm__)
xmm0
=
vabsq_s16
(
rxF
[
i
]);
xmm0
=
vsubq_s16
(
ch_mag
[
i
],
xmm0
);
// lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
llr16
[
0
]
=
vgetq_lane_s16
(
rxF
[
i
],
0
);
llr16
[
1
]
=
vgetq_lane_s16
(
xmm0
,
0
);
llr16
[
2
]
=
vgetq_lane_s16
(
rxF
[
i
],
1
);
llr16
[
3
]
=
vgetq_lane_s16
(
xmm0
,
1
);
llr16
[
4
]
=
vgetq_lane_s16
(
rxF
[
i
],
2
);
llr16
[
5
]
=
vgetq_lane_s16
(
xmm0
,
2
);
llr16
[
6
]
=
vgetq_lane_s16
(
rxF
[
i
],
2
);
llr16
[
7
]
=
vgetq_lane_s16
(
xmm0
,
3
);
llr16
[
8
]
=
vgetq_lane_s16
(
rxF
[
i
],
4
);
llr16
[
9
]
=
vgetq_lane_s16
(
xmm0
,
4
);
llr16
[
10
]
=
vgetq_lane_s16
(
rxF
[
i
],
5
);
llr16
[
11
]
=
vgetq_lane_s16
(
xmm0
,
5
);
llr16
[
12
]
=
vgetq_lane_s16
(
rxF
[
i
],
6
);
llr16
[
13
]
=
vgetq_lane_s16
(
xmm0
,
6
);
llr16
[
14
]
=
vgetq_lane_s16
(
rxF
[
i
],
7
);
llr16
[
15
]
=
vgetq_lane_s16
(
xmm0
,
7
);
llr16
+=
16
;
#endif
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
}
//----------------------------------------------------------------------------------------------
// 64-QAM
//----------------------------------------------------------------------------------------------
void
mch_64qam_llr
(
LTE_DL_FRAME_PARMS
*
frame_parms
,
int
**
rxdataF_comp
,
short
*
dlsch_llr
,
int
**
dl_ch_mag
,
int
**
dl_ch_magb
,
unsigned
char
symbol
,
short
**
llr_save
)
{
#if defined(__x86_64__) || defined(__i386__)
__m128i
xmm1
,
xmm2
,
*
ch_mag
,
*
ch_magb
;
__m128i
*
rxF
=
(
__m128i
*
)
&
rxdataF_comp
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
#elif defined(__arm__)
int16x8_t
xmm1
,
xmm2
,
*
ch_mag
,
*
ch_magb
;
int16x8_t
*
rxF
=
(
int16x8_t
*
)
&
rxdataF_comp
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
#endif
int
i
,
len
,
len2
;
// int j=0;
unsigned
char
len_mod4
;
short
*
llr
;
int16_t
*
llr2
;
if
(
symbol
==
2
)
llr
=
dlsch_llr
;
else
llr
=
*
llr_save
;
#if defined(__x86_64__) || defined(__i386__)
ch_mag
=
(
__m128i
*
)
&
dl_ch_mag
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
ch_magb
=
(
__m128i
*
)
&
dl_ch_magb
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
#elif defined(__arm__)
ch_mag
=
(
int16x8_t
*
)
&
dl_ch_mag
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
ch_magb
=
(
int16x8_t
*
)
&
dl_ch_magb
[
0
][(
symbol
*
frame_parms
->
N_RB_DL
*
12
)];
#endif
if
((
symbol
==
2
)
||
(
symbol
==
6
)
||
(
symbol
==
10
))
{
len
=
frame_parms
->
N_RB_DL
*
6
;
}
else
{
len
=
frame_parms
->
N_RB_DL
*
12
;
}
llr2
=
llr
;
llr
+=
(
len
*
6
);
len_mod4
=
len
&
3
;
len2
=
len
>>
2
;
// length in quad words (4 REs)
len2
+=
(
len_mod4
?
0
:
1
);
for
(
i
=
0
;
i
<
len2
;
i
++
)
{
#if defined(__x86_64__) || defined(__i386__)
xmm1
=
_mm_abs_epi16
(
rxF
[
i
]);
xmm1
=
_mm_subs_epi16
(
ch_mag
[
i
],
xmm1
);
xmm2
=
_mm_abs_epi16
(
xmm1
);
xmm2
=
_mm_subs_epi16
(
ch_magb
[
i
],
xmm2
);
#elif defined(__arm__)
xmm1
=
vabsq_s16
(
rxF
[
i
]);
xmm1
=
vsubq_s16
(
ch_mag
[
i
],
xmm1
);
xmm2
=
vabsq_s16
(
xmm1
);
xmm2
=
vsubq_s16
(
ch_magb
[
i
],
xmm2
);
#endif
/*
printf("pmch i: %d => mag (%d,%d) (%d,%d)\n",i,((short *)&ch_mag[i])[0],((short *)&ch_magb[i])[0],
((short *)&rxF[i])[0],((short *)&rxF[i])[1]);
*/
// loop over all LLRs in quad word (24 coded bits)
/*
for (j=0;j<8;j+=2) {
llr2[0] = ((short *)&rxF[i])[j];
llr2[1] = ((short *)&rxF[i])[j+1];
llr2[2] = _mm_extract_epi16(xmm1,j);
llr2[3] = _mm_extract_epi16(xmm1,j+1);//((short *)&xmm1)[j+1];
llr2[4] = _mm_extract_epi16(xmm2,j);//((short *)&xmm2)[j];
llr2[5] = _mm_extract_epi16(xmm2,j+1);//((short *)&xmm2)[j+1];
llr2+=6;
}
*/
llr2
[
0
]
=
((
short
*
)
&
rxF
[
i
])[
0
];
llr2
[
1
]
=
((
short
*
)
&
rxF
[
i
])[
1
];
#if defined(__x86_64__) || defined(__i386__)
llr2
[
2
]
=
_mm_extract_epi16
(
xmm1
,
0
);
llr2
[
3
]
=
_mm_extract_epi16
(
xmm1
,
1
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
_mm_extract_epi16
(
xmm2
,
0
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
_mm_extract_epi16
(
xmm2
,
1
);
//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2
[
2
]
=
vgetq_lane_s16
(
xmm1
,
0
);
llr2
[
3
]
=
vgetq_lane_s16
(
xmm1
,
1
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
vgetq_lane_s16
(
xmm2
,
0
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
vgetq_lane_s16
(
xmm2
,
1
);
//((short *)&xmm2)[j+1];
#endif
llr2
+=
6
;
llr2
[
0
]
=
((
short
*
)
&
rxF
[
i
])[
2
];
llr2
[
1
]
=
((
short
*
)
&
rxF
[
i
])[
3
];
#if defined(__x86_64__) || defined(__i386__)
llr2
[
2
]
=
_mm_extract_epi16
(
xmm1
,
2
);
llr2
[
3
]
=
_mm_extract_epi16
(
xmm1
,
3
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
_mm_extract_epi16
(
xmm2
,
2
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
_mm_extract_epi16
(
xmm2
,
3
);
//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2
[
2
]
=
vgetq_lane_s16
(
xmm1
,
2
);
llr2
[
3
]
=
vgetq_lane_s16
(
xmm1
,
3
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
vgetq_lane_s16
(
xmm2
,
2
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
vgetq_lane_s16
(
xmm2
,
3
);
//((short *)&xmm2)[j+1];
#endif
llr2
+=
6
;
llr2
[
0
]
=
((
short
*
)
&
rxF
[
i
])[
4
];
llr2
[
1
]
=
((
short
*
)
&
rxF
[
i
])[
5
];
#if defined(__x86_64__) || defined(__i386__)
llr2
[
2
]
=
_mm_extract_epi16
(
xmm1
,
4
);
llr2
[
3
]
=
_mm_extract_epi16
(
xmm1
,
5
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
_mm_extract_epi16
(
xmm2
,
4
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
_mm_extract_epi16
(
xmm2
,
5
);
//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2
[
2
]
=
vgetq_lane_s16
(
xmm1
,
4
);
llr2
[
3
]
=
vgetq_lane_s16
(
xmm1
,
5
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
vgetq_lane_s16
(
xmm2
,
4
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
vgetq_lane_s16
(
xmm2
,
5
);
//((short *)&xmm2)[j+1];
#endif
llr2
+=
6
;
llr2
[
0
]
=
((
short
*
)
&
rxF
[
i
])[
6
];
llr2
[
1
]
=
((
short
*
)
&
rxF
[
i
])[
7
];
#if defined(__x86_64__) || defined(__i386__)
llr2
[
2
]
=
_mm_extract_epi16
(
xmm1
,
6
);
llr2
[
3
]
=
_mm_extract_epi16
(
xmm1
,
7
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
_mm_extract_epi16
(
xmm2
,
6
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
_mm_extract_epi16
(
xmm2
,
7
);
//((short *)&xmm2)[j+1];
#elif defined(__arm__)
llr2
[
2
]
=
vgetq_lane_s16
(
xmm1
,
6
);
llr2
[
3
]
=
vgetq_lane_s16
(
xmm1
,
7
);
//((short *)&xmm1)[j+1];
llr2
[
4
]
=
vgetq_lane_s16
(
xmm2
,
6
);
//((short *)&xmm2)[j];
llr2
[
5
]
=
vgetq_lane_s16
(
xmm2
,
7
);
//((short *)&xmm2)[j+1];
#endif
llr2
+=
6
;
}
*
llr_save
=
llr
;
#if defined(__x86_64__) || defined(__i386__)
_mm_empty
();
_m_empty
();
#endif
}
int
avg_pmch
[
4
];
int
rx_pmch
(
PHY_VARS_UE
*
ue
,
unsigned
char
eNB_id
,
uint8_t
subframe
,
unsigned
char
symbol
)
{
LTE_UE_COMMON
*
common_vars
=
&
ue
->
common_vars
;
LTE_UE_PDSCH
**
pdsch_vars
=
&
ue
->
pdsch_vars_MCH
[
eNB_id
];
LTE_DL_FRAME_PARMS
*
frame_parms
=
&
ue
->
frame_parms
;
LTE_UE_DLSCH_t
**
dlsch
=
&
ue
->
dlsch_MCH
[
eNB_id
];
int
avgs
,
aarx
;
//printf("*********************mch: symbol %d\n",symbol);
mch_extract_rbs
(
common_vars
->
common_vars_rx_data_per_thread
[
ue
->
current_thread_id
[
subframe
]].
rxdataF
,
common_vars
->
common_vars_rx_data_per_thread
[
ue
->
current_thread_id
[
subframe
]].
dl_ch_estimates
[
eNB_id
],
pdsch_vars
[
eNB_id
]
->
rxdataF_ext
,
pdsch_vars
[
eNB_id
]
->
dl_ch_estimates_ext
,
symbol
,
subframe
,
frame_parms
);
if
(
symbol
==
2
)
{
mch_channel_level
(
pdsch_vars
[
eNB_id
]
->
dl_ch_estimates_ext
,
frame_parms
,
avg_pmch
,
symbol
,
frame_parms
->
N_RB_DL
);
}
avgs
=
0
;
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
avgs
=
cmax
(
avgs
,
avg_pmch
[
aarx
]);
if
(
get_Qm
(
dlsch
[
0
]
->
harq_processes
[
0
]
->
mcs
)
==
2
)
pdsch_vars
[
eNB_id
]
->
log2_maxh
=
(
log2_approx
(
avgs
)
/
2
)
;
// + 2
else
pdsch_vars
[
eNB_id
]
->
log2_maxh
=
(
log2_approx
(
avgs
)
/
2
);
// + 5;// + 2
mch_channel_compensation
(
pdsch_vars
[
eNB_id
]
->
rxdataF_ext
,
pdsch_vars
[
eNB_id
]
->
dl_ch_estimates_ext
,
pdsch_vars
[
eNB_id
]
->
dl_ch_mag0
,
pdsch_vars
[
eNB_id
]
->
dl_ch_magb0
,
pdsch_vars
[
eNB_id
]
->
rxdataF_comp0
,
frame_parms
,
symbol
,
get_Qm
(
dlsch
[
0
]
->
harq_processes
[
0
]
->
mcs
),
pdsch_vars
[
eNB_id
]
->
log2_maxh
);
if
(
frame_parms
->
nb_antennas_rx
>
1
)
mch_detection_mrc
(
frame_parms
,
pdsch_vars
[
eNB_id
]
->
rxdataF_comp0
,
pdsch_vars
[
eNB_id
]
->
dl_ch_mag0
,
pdsch_vars
[
eNB_id
]
->
dl_ch_magb0
,
symbol
);
switch
(
get_Qm
(
dlsch
[
0
]
->
harq_processes
[
0
]
->
mcs
))
{
case
2
:
mch_qpsk_llr
(
frame_parms
,
pdsch_vars
[
eNB_id
]
->
rxdataF_comp0
,
pdsch_vars
[
eNB_id
]
->
llr
[
0
],
symbol
,
pdsch_vars
[
eNB_id
]
->
llr128
);
break
;
case
4
:
mch_16qam_llr
(
frame_parms
,
pdsch_vars
[
eNB_id
]
->
rxdataF_comp0
,
pdsch_vars
[
eNB_id
]
->
llr
[
0
],
pdsch_vars
[
eNB_id
]
->
dl_ch_mag0
,
symbol
,
pdsch_vars
[
eNB_id
]
->
llr128
);
break
;
case
6
:
mch_64qam_llr
(
frame_parms
,
pdsch_vars
[
eNB_id
]
->
rxdataF_comp0
,
pdsch_vars
[
eNB_id
]
->
llr
[
0
],
pdsch_vars
[
eNB_id
]
->
dl_ch_mag0
,
pdsch_vars
[
eNB_id
]
->
dl_ch_magb0
,
symbol
,
pdsch_vars
[
eNB_id
]
->
llr128
);
break
;
}
return
(
0
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment