Matlab Toolbox - 4G/LTE
The first thing a UE learns about a cell is its PCI, the physical-layer cell identity. Every other downlink channel depends on it, from the CRS positions to the scrambling of the PDCCH and PDSCH. This page builds a full radio frame with PCI 10, and then lets the function lteCellSearch find that PCI again, first from the clean waveform and then after a fading channel.
Followings are the topics to be covered in this page.
- Detecting PCI for Ideal Signal
- Detecting PCI for Faded Signal
- How the PCI is carried by PSS and SSS
- Reference
Detecting PCI for Ideal Signal
Can the toolbox recover the PCI from nothing but the time-domain waveform? This example answers that for the easiest case, a waveform that has passed through no channel at all. The transmitter uses 6 RB, one antenna and NCellID = 10.
% First you have to define properites of a eNodeB.
% NDLRB indicate System Bandwith in the unit of RBs.
% NDLRB 6 = 1.4 Mhz, NDLRB 15 = 3.0 Mhz, NDLRB 25 = 5.0 Mhz,
% NDLRB 50 = 10 Mhz, NDLRB 75 = 15 Mhz, NDLRB 100 = 20 Mhz
% CellRefP indicate number of downlink Antenna. CellRefP = 1 means 1 transmission antenna (SISO)
% NCellID indicate PCI (Physical Cell Identity) of the Cell
% NSubframe indicate the subframe number.
enb.CyclicPrefix = 'Normal';
enb.PHICHDuration = 'Normal';
enb.Ng = 'Sixth';
enb.NDLRB = 6;
enb.CellRefP = 1;
enb.DuplexMode = 'FDD';
enb.NFrame = 0;
enb.NCellID = 10;
txFrameGrid = [];
for subframeNo = 0:9
enb.NSubframe = subframeNo;
enb.CFI = 1;
PHICH_Group_Index = 0;
PHICH_Sequence_Index = 1;
HARQ_Indicator_Value = 0; % 0 = NACK, 1 = ACK
dci.NDLRB = enb.NDLRB;
dci.DCIFormat = 'Format1A';
dci.AllocationType = 0;
dci.Allocation.RIV = 18;
dci.ModCoding = 10;
dci.HARQNo = 0;
dci.NewData = 0;
dci.TPCPUCCH = 0;
dci.DuplexMode = 'FDD';
dci.NTxAnts = 1;
[dciMessage,dciMessageBits] = lteDCI(enb,dci);
C_RNTI = 100;
pdcchConfig.RNTI = C_RNTI;
pdcchConfig.PDCCHFormat = 0;
codedDciBits = lteDCIEncode(pdcchConfig, dciMessageBits);
pdcchDims = ltePDCCHInfo(enb);
pdcchBits = -1*ones(pdcchDims.MTot, 1);
candidates = ltePDCCHSpace(enb, pdcchConfig, {'bits', '1based'});
pdcchBits ( candidates(1, 1) : candidates(1, 2) ) = codedDciBits;
pdcch_sym = ltePDCCH(enb, pdcchBits);
pdcch_sym_ind = ltePDCCHIndices(enb,{'1based','re'});
pdcch_sym_arrayIndex = 0:length(pdcch_sym)-1;
% Generating PDSCH Symbols
pdsch.NTxAnts = 1;
pdsch.NLayers = 1;
pdsch.TxScheme = 'Port0';
pdsch.Modulation = {'16QAM'};
pdsch.RV = 0;
pdsch.RNTI = C_RNTI;
START_RB = 0;
N_RB = 4; %enb.NDLRB;
pdsch_prbs = (START_RB:(START_RB+N_RB-1)).';
[pdsch_sym_ind,pdschIndInfo] = ltePDSCHIndices(enb,pdsch,pdsch_prbs,{'1based','re'});
codedTrBlkSize = pdschIndInfo.G;
dlschTransportBlk = round(rand(1,codedTrBlkSize));
codeword = lteDLSCH(enb,pdsch,codedTrBlkSize,dlschTransportBlk);
pdsch_sym = ltePDSCH(enb,pdsch,codeword);
pdsch_sym_arrayIndex = 0:length(pdsch_sym)-1;
%fill in the resource grid
resourceGrid = lteDLResourceGrid(enb);
rsAnt0 = lteCellRS(enb,0);
indAnt0 = lteCellRSIndices(enb,0);
resourceGrid(indAnt0) = rsAnt0;
mib_bits = lteMIB(enb);
bch_cw = lteBCH(enb,mib_bits);
pss = ltePSS(enb);
pss_arrayIndex = 0:length(pss)-1;
pss_sym_ind = ltePSSIndices(enb,0,{'1based','re'});
sss = lteSSS(enb);
sss_arrayIndex = 0:length(sss)-1;
sss_sym_ind = lteSSSIndices(enb,0,{'1based','re'});
cfi_cw = lteCFI(enb);
pcfich_sym = ltePCFICH(enb,cfi_cw);
pcfich_sym_arrayIndex = 0:length(pcfich_sym)-1;
pcfich_sym_ind = ltePCFICHIndices(enb,{'1based','re'});
phich_sym = ltePHICH(enb,[PHICH_Group_Index,PHICH_Sequence_Index,HARQ_Indicator_Value]);
phich_sym_arrayIndex = 0:length(phich_sym)-1;
phich_sym_ind = ltePHICHIndices(enb,{'1based','re'});
pbch_sym = ltePBCH(enb,bch_cw);
pbch_sym_arrayIndex = 0:length(pbch_sym)-1;
pbch_sym_ind = ltePBCHIndices(enb,{'1based','re'});
pss_scale = 1.0;
sss_scale = 1.0;
phich_scale = 1.0;
pcfich_scale = 1.0;
pbch_scale = 1.0;
pdcch_scale = 1.0;
pdsch_scale = 1.0;
resourceGrid(pss_sym_ind) = pss_scale .* pss;
resourceGrid(sss_sym_ind) = sss_scale .* sss;
resourceGrid(pcfich_sym_ind) = pcfich_scale .* pcfich_sym;
resourceGrid(phich_sym_ind) = phich_scale .* phich_sym;
resourceGrid(pbch_sym_ind) = pbch_scale .* pbch_sym(1:length(pbch_sym_ind));
resourceGrid(pdcch_sym_ind) = pdcch_scale .* pdcch_sym;
resourceGrid(pdsch_sym_ind) = pdsch_scale .* pdsch_sym;
txFrameGrid = [txFrameGrid resourceGrid];
end;
[tx_waveform,tx_waveform_info] = lteOFDMModulate(enb,txFrameGrid);
[frame_offset,offset_corr]=lteDLFrameOffset(enb,tx_waveform);
dlConfig.NDLRB = enb.NDLRB;
dlConfig.CyclicPrefix = enb.CyclicPrefix;
dlConfig.NSubframe = 0;
dlConfig.DuplexMode = enb.DuplexMode;
freq_offset = lteFrequencyOffset(dlConfig,tx_waveform);
enb.TotSubframes = 10;
PCI = lteCellSearch(enb,tx_waveform)
The loop builds the 10 subframes of one radio frame, with the same channels as on the radio frame page of this series. It joins the grids with txFrameGrid = [txFrameGrid resourceGrid]. The function lteOFDMModulate turns the frame into tx_waveform. The code then calls lteDLFrameOffset and lteFrequencyOffset, which are the subjects of the Frame Offset page and the frequency offset page, but it does not use their results.
The last call does the detection. The function lteCellSearch correlates the waveform with the three possible PSS sequences, which gives the identity within the group. It then tests the 168 SSS sequences for that identity, which gives the group. The result below is 10, the NCellID that the transmitter used.
Result = |
|
10 |
Output of lteCellSearch for the ideal signal. The detected PCI is 10.
One radio frame of 10 subframes : built in a loop and OFDM modulated.lteCellSearch returns 10 : the NCellID of the transmitter.Frame and frequency offset computed but not used : the cell search does not need them here.
Detecting PCI for Faded Signal
A clean waveform is the easy case. This example adds an EVA fading channel between the transmitter and the cell search, which is closer to what a UE receives. The transmitter code is the same as in the ideal case.
% First you have to define properites of a eNodeB.
% NDLRB indicate System Bandwith in the unit of RBs.
% NDLRB 6 = 1.4 Mhz, NDLRB 15 = 3.0 Mhz, NDLRB 25 = 5.0 Mhz,
% NDLRB 50 = 10 Mhz, NDLRB 75 = 15 Mhz, NDLRB 100 = 20 Mhz
% CellRefP indicate number of downlink Antenna. CellRefP = 1 means 1 transmission antenna (SISO)
% NCellID indicate PCI (Physical Cell Identity) of the Cell
% NSubframe indicate the subframe number.
enb.CyclicPrefix = 'Normal';
enb.PHICHDuration = 'Normal';
enb.Ng = 'Sixth';
enb.NDLRB = 6;
enb.CellRefP = 1;
enb.DuplexMode = 'FDD';
enb.NFrame = 0;
enb.NCellID = 10;
txFrameGrid = [];
for subframeNo = 0:9
enb.NSubframe = subframeNo;
enb.CFI = 1;
PHICH_Group_Index = 0;
PHICH_Sequence_Index = 1;
HARQ_Indicator_Value = 0; % 0 = NACK, 1 = ACK
dci.NDLRB = enb.NDLRB;
dci.DCIFormat = 'Format1A';
dci.AllocationType = 0;
dci.Allocation.RIV = 18;
dci.ModCoding = 10;
dci.HARQNo = 0;
dci.NewData = 0;
dci.TPCPUCCH = 0;
dci.DuplexMode = 'FDD';
dci.NTxAnts = 1;
[dciMessage,dciMessageBits] = lteDCI(enb,dci);
C_RNTI = 100;
pdcchConfig.RNTI = C_RNTI;
pdcchConfig.PDCCHFormat = 0;
codedDciBits = lteDCIEncode(pdcchConfig, dciMessageBits);
pdcchDims = ltePDCCHInfo(enb);
pdcchBits = -1*ones(pdcchDims.MTot, 1);
candidates = ltePDCCHSpace(enb, pdcchConfig, {'bits', '1based'});
pdcchBits ( candidates(1, 1) : candidates(1, 2) ) = codedDciBits;
pdcch_sym = ltePDCCH(enb, pdcchBits);
pdcch_sym_ind = ltePDCCHIndices(enb,{'1based','re'});
pdcch_sym_arrayIndex = 0:length(pdcch_sym)-1;
% Generating PDSCH Symbols
pdsch.NTxAnts = 1;
pdsch.NLayers = 1;
pdsch.TxScheme = 'Port0';
pdsch.Modulation = {'16QAM'};
pdsch.RV = 0;
pdsch.RNTI = C_RNTI;
START_RB = 0;
N_RB = 4; %enb.NDLRB;
pdsch_prbs = (START_RB:(START_RB+N_RB-1)).';
[pdsch_sym_ind,pdschIndInfo] = ltePDSCHIndices(enb,pdsch,pdsch_prbs,{'1based','re'});
codedTrBlkSize = pdschIndInfo.G;
dlschTransportBlk = round(rand(1,codedTrBlkSize));
codeword = lteDLSCH(enb,pdsch,codedTrBlkSize,dlschTransportBlk);
pdsch_sym = ltePDSCH(enb,pdsch,codeword);
pdsch_sym_arrayIndex = 0:length(pdsch_sym)-1;
%fill in the resource grid
resourceGrid = lteDLResourceGrid(enb);
rsAnt0 = lteCellRS(enb,0);
indAnt0 = lteCellRSIndices(enb,0);
resourceGrid(indAnt0) = rsAnt0;
mib_bits = lteMIB(enb);
bch_cw = lteBCH(enb,mib_bits);
pss = ltePSS(enb);
pss_arrayIndex = 0:length(pss)-1;
pss_sym_ind = ltePSSIndices(enb,0,{'1based','re'});
sss = lteSSS(enb);
sss_arrayIndex = 0:length(sss)-1;
sss_sym_ind = lteSSSIndices(enb,0,{'1based','re'});
cfi_cw = lteCFI(enb);
pcfich_sym = ltePCFICH(enb,cfi_cw);
pcfich_sym_arrayIndex = 0:length(pcfich_sym)-1;
pcfich_sym_ind = ltePCFICHIndices(enb,{'1based','re'});
phich_sym = ltePHICH(enb,[PHICH_Group_Index,PHICH_Sequence_Index,HARQ_Indicator_Value]);
phich_sym_arrayIndex = 0:length(phich_sym)-1;
phich_sym_ind = ltePHICHIndices(enb,{'1based','re'});
pbch_sym = ltePBCH(enb,bch_cw);
pbch_sym_arrayIndex = 0:length(pbch_sym)-1;
pbch_sym_ind = ltePBCHIndices(enb,{'1based','re'});
pss_scale = 1.0;
sss_scale = 1.0;
phich_scale = 1.0;
pcfich_scale = 1.0;
pbch_scale = 1.0;
pdcch_scale = 1.0;
pdsch_scale = 1.0;
resourceGrid(pss_sym_ind) = pss_scale .* pss;
resourceGrid(sss_sym_ind) = sss_scale .* sss;
resourceGrid(pcfich_sym_ind) = pcfich_scale .* pcfich_sym;
resourceGrid(phich_sym_ind) = phich_scale .* phich_sym;
resourceGrid(pbch_sym_ind) = pbch_scale .* pbch_sym(1:length(pbch_sym_ind));
resourceGrid(pdcch_sym_ind) = pdcch_scale .* pdcch_sym;
resourceGrid(pdsch_sym_ind) = pdsch_scale .* pdsch_sym;
txFrameGrid = [txFrameGrid resourceGrid];
end;
[tx_waveform,tx_waveform_info] = lteOFDMModulate(enb,txFrameGrid);
chcfg.Seed = 1;
chcfg.DelayProfile = 'EVA';
chcfg.NRxAnts = 1;
chcfg.InitPhase = 0;
chcfg.ModelType = 'GMEDS';
chcfg.NTerms = 16;
chcfg.NormalizeTxAnts = 'On';
chcfg.NormalizePathGains = 'On';
chcfg.DopplerFreq = 10;
chcfg.MIMOCorrelation = 'Low';
chcfg.SamplingRate = tx_waveform_info.SamplingRate;
chcfg.InitTime = 0;
rx_waveform = lteFadingChannel(chcfg,tx_waveform);
[frame_offset,offset_corr]=lteDLFrameOffset(enb,rx_waveform);
dlConfig.NDLRB = enb.NDLRB;
dlConfig.CyclicPrefix = enb.CyclicPrefix;
dlConfig.NSubframe = 0;
dlConfig.DuplexMode = enb.DuplexMode;
freq_offset = lteFrequencyOffset(dlConfig,rx_waveform);
enb.TotSubframes = 10;
PCI = lteCellSearch(enb,tx_waveform)
The channel uses the EVA delay profile with a Doppler frequency of 10 Hz and one receive antenna, and lteFadingChannel produces rx_waveform. The Fading page explains these parameters. The code then measures the frame offset and the frequency offset on rx_waveform.
The cell search itself, however, still reads tx_waveform: PCI = lteCellSearch(enb,tx_waveform). The result of 10 below is therefore the result for the clean waveform again, not for the faded one. To test the faded signal, the call should read PCI = lteCellSearch(enb,rx_waveform). The code on this page is left as it was run, because the result was produced with it.
Result = |
|
10 |
Output of lteCellSearch in the faded example. The call passes tx_waveform, so this is the result for the signal before the channel.
EVA channel, 10 Hz Doppler, one Rx antenna : lteFadingChannel gives rx_waveform.lteCellSearch reads tx_waveform : so the result does not test the faded signal.Use rx_waveform in the call : to detect the PCI after the channel.
How the PCI is carried by PSS and SSS
Why does the cell search take two steps? The answer is in how 36.211 builds the PCI. Each step of the search recovers one of the two numbers that make up the PCI.
36.211 v19.3.0 clause 6.11 defines 504 PCIs, grouped into 168 cell-identity groups of 3 identities each. The PCI is 3 NID(1) + NID(2), where NID(1) is the group, from 0 to 167, and NID(2) is the identity within the group, from 0 to 2. The PSS carries NID(2) through the root of its Zadoff-Chu sequence. The SSS carries NID(1) through the pair of cyclic shifts m0 and m1, and it is scrambled with a sequence that depends on NID(2).
For the PCI of this page, the values are as follows.
Quantity | Value for PCI 10 | Carried by or defined in |
NID(2) | 10 mod 3 = 1 | PSS |
PSS root index u | 29 | 36.211 Table 6.11.1.1-1 |
NID(1) | floor(10 / 3) = 3 | SSS |
m0, m1 | 3, 4 | 36.211 Table 6.11.2.1-1 |
That is why the search runs in this order. The UE first finds the PSS, which has only 3 candidates and also gives the timing of slots 0 and 10. With NID(2) known, the SSS has 168 candidates, and its two halves differ between subframes 0 and 5, which also gives the frame timing. The PSS and SSS pages show both sequences for other PCIs.
PCI = 3 NID(1) + NID(2) : 504 values.PSS gives NID(2) : root 29 for PCI 10.SSS gives NID(1) : group 3 for PCI 10.
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 6.11, Synchronization signals, Tables 6.11.1.1-1 and 6.11.2.1-1