Matlab Toolbox - 4G/LTE
PUCCH format 1 and its variants 1a and 1b carry the scheduling request and the HARQ-ACK of a UE. The information is at most two bits, so the channel spends its resources on spreading rather than on coding. This page generates the symbols with ltePUCCH1 and ltePUCCH1DRS, and shows where they land in the uplink resource grid.
Description/explanation will come later !
Followings are the topics to be covered in this page.
Generation of PUCCH Format 1 Symbol
How can many UEs share the same resource block for their ACK and NACK? Format 1 answers with code division. Each UE gets its own cyclic shift of a length-12 sequence and its own orthogonal cover, and the resource index selects both.
ue1.NCellID = 0;
ue1.CyclicPrefixUL = 'Normal';
ue1.NSubframe = 0;
ue1.Hopping = 'Off';
ue1.NULRB = 6;
ue1.Shortened = 0;
ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0;
pucch1.DeltaShift = 1;
pucch1.CyclicShifts = 6;
pucch1.ResourceSize = 0;
hi = [0 0];
pucch1_sym = ltePUCCH1(ue1,pucch1,hi);
pucch1_sym_arrayIndex = 0:length(pucch1_sym)-1;
dmrs1_sym = ltePUCCH1DRS(ue1,pucch1);
dmrs1_sym_arrayIndex = 0:length(dmrs1_sym)-1;
dmrs1_sym_ind = ltePUCCH1DRSIndices(ue1,pucch1);
subplot(2,3,1);
plot(real(pucch1_sym),imag(pucch1_sym),'ro','MarkerFaceColor',[1 0 0]);
title('Constellation');
subplot(2,3,[2 3]);
plot(pucch1_sym_arrayIndex,real(pucch1_sym),'ro-',pucch1_sym_arrayIndex,imag(pucch1_sym),'bo-');
xlim([0 max(pucch1_sym_arrayIndex)]);
title('PUCCH index vs PUCCH value. Red -> real, Blue -> Imaginary');
subplot(2,3,4);
plot(real(dmrs1_sym),imag(dmrs1_sym),'ro','MarkerFaceColor',[1 0 0]);
title('Constellation');
subplot(2,3,[5 6]);
plot(dmrs1_sym_arrayIndex,real(dmrs1_sym),'ro-',dmrs1_sym_arrayIndex,imag(dmrs1_sym),'bo-');
xlim([0 max(dmrs1_sym_arrayIndex)]);
title('DMRS index vs DMRS value. Red -> real, Blue -> Imaginary');
The pucch1 fields map onto the higher layer parameters of 36.211. ResourceIdx is the resource index nPUCCH(1), DeltaShift is ΔshiftPUCCH, CyclicShifts is Ncs(1) and ResourceSize is NRB(2). The input hi = [0 0] holds two HARQ bits. So the output is format 1b with one QPSK symbol, as 36.211 v19.3.0 Table 5.4-1 lists. One bit gives format 1a with BPSK, and an empty hi gives format 1, which signals a scheduling request by its presence alone.
That single symbol is multiplied by a cyclically shifted sequence of length 12. An orthogonal cover of length 4 then spreads it across the data symbols of a slot. With the normal cyclic prefix, each slot has 4 data symbols and 3 DMRS symbols. So ltePUCCH1 returns 12 x 4 x 2 = 96 symbols for the subframe, and ltePUCCH1DRS returns 12 x 3 x 2 = 72.
The plots below use three settings, which the parameter table above each plot lists. The upper half of each plot shows the 96 PUCCH symbols, and the lower half shows the 72 DMRS symbols.
|
ue1.NCellID = 0; ue1.NSubframe = 0; ue1.NULRB = 6; ue1.Shortened = 0; ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0; pucch1.DeltaShift = 1; pucch1.CyclicShifts = 6; pucch1.ResourceSize = 0;
hi = [0 0]; |
|
|
|
|
ResourceIdx = 0, DeltaShift = 1. Every PUCCH and DMRS symbol lies on the unit circle, as the constellations on the left show.
|
ue1.NCellID = 0; ue1.NSubframe = 0; ue1.NULRB = 6; ue1.Shortened = 0; ue1.NTxAnts = 1;
pucch1.ResourceIdx = 1; pucch1.DeltaShift = 1; pucch1.CyclicShifts = 6; pucch1.ResourceSize = 0;
hi = [0 0]; |
|
|
|
|
ResourceIdx = 1, DeltaShift = 1. The constellation keeps its points, but the sequence of values is different from the plot above.
|
ue1.NCellID = 0; ue1.NSubframe = 0; ue1.NULRB = 6; ue1.Shortened = 0; ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0; pucch1.DeltaShift = 2; pucch1.CyclicShifts = 6; pucch1.ResourceSize = 0;
hi = [0 0]; |
|
|
|
|
ResourceIdx = 0, DeltaShift = 2. The sequence is the same as for ResourceIdx = 0 and DeltaShift = 1.
The resource index sets the cyclic shift and the orthogonal cover index by the rules of 36.211 clause 5.4.1. With ResourceIdx = 0, both come out as 0 for any DeltaShift, which is why the two plots with ResourceIdx = 0 match. With ResourceIdx = 1 and DeltaShift = 1, the cyclic shift moves by one step. Every value changes, although the constellation points stay the same. DeltaShift sets the spacing of the cyclic shifts between neighbouring resources, so it matters only from ResourceIdx = 1 upward.
hi = [0 0] gives format 1b : one QPSK symbol for two HARQ bits.96 PUCCH symbols, 72 DMRS symbols : 12 subcarriers, 4 data and 3 DMRS symbols per slot, 2 slots.ResourceIdx selects the cyclic shift and cover : so it separates UEs on the same RB.ResourceIdx 0 ignores DeltaShift : both settings give cyclic shift 0 and cover 0.
Symbol to RE Mapping
Where does the PUCCH go in the uplink grid? It takes one RB in each slot, near opposite edges of the carrier. The two halves of the subframe therefore see different parts of the channel. This section maps the symbols into the grid and changes ResourceSize to move them.
ue1.NCellID = 0;
ue1.CyclicPrefixUL = 'Normal';
ue1.NSubframe = 0;
ue1.Hopping = 'Off';
ue1.NULRB = 6;
ue1.Shortened = 0;
ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0;
pucch1.DeltaShift = 1;
pucch1.CyclicShifts = 6;
pucch1.ResourceSize = 0;
hi = [0 0];
pucch1_sym = ltePUCCH1(ue1,pucch1,hi);
pucch1_sym_arrayIndex = 0:length(pucch1_sym)-1;
pucch1_sym_ind = ltePUCCH1Indices(ue1,pucch1);
dmrs1_sym = ltePUCCH1DRS(ue1,pucch1);
dmrs1_sym_arrayIndex = 0:length(dmrs1_sym)-1;
dmrs1_sym_ind = ltePUCCH1DRSIndices(ue1,pucch1);
resourceGridUL = lteULResourceGrid(ue1);
pucch1_scale = 1.0;
dmrs1_scale = 0.5;
resourceGridUL(pucch1_sym_ind) = pucch1_scale * pucch1_sym;
resourceGridUL(dmrs1_sym_ind) = dmrs1_scale * dmrs1_sym;
resourceGridUL = [ resourceGridUL resourceGridUL(:,13)];
resourceGridUL = [ resourceGridUL; resourceGridUL((ue1.NULRB*12-1),:) ];
xStep = 0:14;
yStep = 0:(ue1.NULRB*12);
surface(xStep,yStep,abs(resourceGridUL));
axis([0 14 0 (ue1.NULRB*12) 0 2]);
view([0,90]);
set(gca,'xtick',[0 6 7 13]);
set(gca,'ytick',[[0:12:ue1.NULRB*12-1] [ue1.NULRB*12-1]]);
The code writes the PUCCH symbols with scale 1.0 and the DMRS with scale 0.5, so the two appear in different colours. The surface function draws one cell between two grid points. So the code appends one extra column and one extra row to show every RE. The x axis marks symbols 0, 6, 7 and 13, the edges of the two slots. The y axis counts the 72 subcarriers of 6 RB.
The plots below show ResourceSize = 0 and 1 side by side, and then 2 and 3.
|
ue1.NCellID = 0; ue1.NSubframe = 0; ue1.NULRB = 6; ue1.Shortened = 0; ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0; pucch1.DeltaShift = 2; pucch1.CyclicShifts = 6; pucch1.ResourceSize = 0;
hi = [0 0]; |
ue1.NCellID = 0; ue1.NSubframe = 0; ue1.NULRB = 6; ue1.Shortened = 0; ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0; pucch1.DeltaShift = 2; pucch1.CyclicShifts = 6; pucch1.ResourceSize = 1;
hi = [0 0]; |
|
|
|
ResourceSize = 0 on the left: RB 0 in slot 0 and RB 5 in slot 1. ResourceSize = 1 on the right: RB 5 in slot 0 and RB 0 in slot 1. The yellow REs carry PUCCH data in symbols 0, 1, 5 and 6 of each slot. The green REs carry DMRS in symbols 2, 3 and 4.
|
ue1.NCellID = 0; ue1.NSubframe = 0; ue1.NULRB = 6; ue1.Shortened = 0; ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0; pucch1.DeltaShift = 2; pucch1.CyclicShifts = 6; pucch1.ResourceSize = 2;
hi = [0 0]; |
ue1.NCellID = 0; ue1.NSubframe = 0; ue1.NULRB = 6; ue1.Shortened = 0; ue1.NTxAnts = 1;
pucch1.ResourceIdx = 0; pucch1.DeltaShift = 2; pucch1.CyclicShifts = 6; pucch1.ResourceSize = 3;
hi = [0 0]; |
|
|
|
ResourceSize = 2 on the left: RB 1 in slot 0 and RB 4 in slot 1. ResourceSize = 3 on the right: RB 4 in slot 0 and RB 1 in slot 1.
The positions follow 36.211 clause 5.4.3. The PUCCH uses the RB index m. In each slot, it goes to RB floor(m/2) counted from the bottom or from the top of the carrier. Even values of m start at the bottom in slot 0, and odd values start at the top. Slot 1 always takes the other edge. For format 1, m equals NRB(2) while the resource index stays inside the first block. Here ResourceIdx = 0 is below 3 x 6 / 2 = 9, so m follows ResourceSize directly.
ResourceSize | m | RB in slot 0 | RB in slot 1 |
0 | 0 | 0 | 5 |
1 | 1 | 5 | 0 |
2 | 2 | 1 | 4 |
3 | 3 | 4 | 1 |
ResourceSize is the number of RBs reserved for PUCCH Format 2 at each edge. Format 1 is placed inward from those RBs, so a larger ResourceSize moves the format 1 region toward the centre of the carrier.
One RB per slot, at opposite edges : the PUCCH hops between slots.Data in symbols 0, 1, 5 and 6, DMRS in 2, 3 and 4 : for each slot with normal CP.ResourceSize is NRB(2) : the RBs reserved for format 2 at the edges.
Disclaimer !
This page is only to show you the overall logics and visualization for various LTE physical layer channels. I haven't investigated much about verifying about the accuracy.
If you think the code is not so efficient, it is 100% my fault. I haven't made any effort for effiecient code. I just tried to create code as simple as possible for the readers. As you know, easy-to-read code is not always efficient for a specific chipset.
If you find any mistake in terms of accuracy, it is also very highly likely be my fault. Not the problem of Matlab tool box itself.
Any comment and corrections if you find any mistake will be welcome and appreciated.
Reference
[1] 3GPP TS 36.211 v19.3.0 - clause 5.4 and Table 5.4-1, clause 5.4.1 PUCCH formats 1, 1a and 1b, clause 5.4.3 Mapping to physical resources, and clause 5.5.2.2 DMRS for PUCCH






