Matlab Toolbox - 4G/LTE

 

 

 

OFDM Symbol Extraction

 

In this example, I will show you how to extract only one OFDM Symbol from a complete radio subframe. (Actually it will show you the whole process of creating a subframe and extract a specific symbols from the subframe).

This tutorial shows you how do plot each OFDM symbol directly from the resourceGrid. This is not for extracting OFDM symbol from OFDM modulcated symbol (timedomain data).

The resource grid of one subframe is a matrix with one row per subcarrier and one column per OFDM symbol. Extracting one OFDM symbol therefore means reading one column of that matrix. The plots then show which channel each RE of the symbol carries.

Followings are the topics to be covered in this page.

SISO - Extracting a OFDM Symbol

What does a single OFDM symbol of an LTE subframe contain? This example builds a full downlink subframe with one antenna and 6 RB, and then plots one symbol of it. The same code is reused in the next section for all 14 symbols.

    % Since PSS is determined by each eNodeB, 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.NCellID = 0;

    enb.NSubframe = 0;

    enb.CFI = 1;

     

    PHICH_Group_Index = 0;

    PHICH_Sequence_Index = 1;

    HARQ_Indicator_Value = 0; % 0 = NACK, 1 = ACK

     

    % Now populate all the information in DCI field as you like. Understanding details of DCI is also pretty huge

    % topics. You would need separate page for DCI for the details.

     

    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;

     

    % once you defined all the detailed fields of DCI, just pass it to lteDCI() function with eNB info as follows,

    % then you will get the bit stream for the DCI.

     

    [dciMessage,dciMessageBits] = lteDCI(enb,dci);

     

    % for this step, you need to set a couple of additional parameters as shown below. C_RNTI will be XORed to CRC bits

    % PDCCHFormat will determined Aggregation Level.

    %          PDCCHFormat 0 indicate Aggregation Level 1

    %          PDCCHFormat 1 indicate Aggregation Level 2

    %          PDCCHFormat 2 indicate Aggregation Level 4

    %          PDCCHFormat 3 indicate Aggregation Level 8

     

    C_RNTI = 100;                         

    pdcchConfig.RNTI = C_RNTI;            

    pdcchConfig.PDCCHFormat = 0;          

     

    % then pass dciMessageBits and pdcchConfig to lteDCIEncode, the you would get the encoded bitstream.

     

    codedDciBits = lteDCIEncode(pdcchConfig, dciMessageBits);

     

    % If you pass the enb into ltePDCCHInfo() function, it will give you the amount of resources that can be allocated

    % for PDCCH allocation. This is not the amount of resource for only one DCI. It will give you the total/maximum

    % amount of the resources that can be allocated for PDCCH.

     

    pdcchDims = ltePDCCHInfo(enb);

     

    % With ltePDCCHSpace, you can get the list of all the possible spaces that can carry PDCCH. In this example,

    % the space were shown in the unit of bits.

     

    pdcchBits = -1*ones(pdcchDims.MTot, 1);

     

    % generate an array with the length that can accommodate all the possible PDCCH bits.

     

    candidates = ltePDCCHSpace(enb, pdcchConfig, {'bits', '1based'});

     

    % select one of the candidate bitSection and assign the codedDcitBits. You can select any candidate bit section,

    % but in this example, I selected the first candidate section.

     

    pdcchBits ( candidates(1, 1) : candidates(1, 2) ) = codedDciBits;

     

    % if pass the encodedBits into ltePDCCH(), it will generate the modulated physical layer symbols.

     

    pdcch_sym = ltePDCCH(enb, pdcchBits);

    pdcch_sym_ind = ltePDCCHIndices(enb,{'1based','re'});

    pdcch_sym_arrayIndex = 0:length(pdcch_sym)-1;

     

     

    % Now we set various parameters defining PDSCH channel. (In real transmission, you would need to create

    % a dci that is corresponding the configuration here. But in this example, I will go without defining DCI)

     

    pdsch.NTxAnts = 1;

    pdsch.NLayers = 1;

    pdsch.TxScheme = 'Port0';

    pdsch.Modulation = {'16QAM'};

    pdsch.RV = 0;

    pdsch.RNTI = C_RNTI;

     

    % Now I have to create a vector carrying the number of PRB indexes that will be used to carry this PDSCH.

    % for example, pdsch_prbs in following section would create a vector [0 1 2 3]

     

    START_RB = 0;

    N_RB = 4;

     

    pdsch_prbs = (START_RB:(START_RB+N_RB-1)).';

     

    % Now we have to generate a bit sequence which would exactly fit to the number of resource elements that are

    % allocated for PDSCH for this specific subframe. To figure out exact Resource Element information, unlike in other

    % channel processing, I would run ltePDSCHIndices() first. As you see in the following code, ltePDSCHIndices()

    % returns the information that would give you the size of transport block size in the unit of bits.

     

    [pdsch_sym_ind,pdschIndInfo] = ltePDSCHIndices(enb,pdsch,pdsch_prbs,{'1based','re'});

    codedTrBlkSize = pdschIndInfo.G;

     

    % now I would create a bit array that carries the user data. In this example, I generated randomly but in real

    % situation, this would carry your user data (e.g, image, movie, files etc)

     

    dlschTransportBlk = round(rand(1,codedTrBlkSize));

     

    % now if you pass all the information to lteDLSCH), it will generate the encoded codeword data for the transport

    % block you defined.

     

    codeword = lteDLSCH(enb,pdsch,codedTrBlkSize,dlschTransportBlk);

     

    % now if you pass the encoded data (codeword) with eNB and pdsch config to ltePDSCH(), you can generate

    % physical layer symbols for the encoded data.

     

    pdsch_sym = ltePDSCH(enb,pdsch,codeword);

    pdsch_sym_arrayIndex = 0:length(pdsch_sym)-1;

     

    % Following is to create an empty resource grid for one subframe.

     

    resourceGrid = lteDLResourceGrid(enb);

     

    % Following is to create symbols for Cell Specific Reference Signal and make a list of resource index for the

    % reference signal.

     

    rsAnt0 = lteCellRS(enb,0);

    indAnt0 = lteCellRSIndices(enb,0);

    resourceGrid(indAnt0) = rsAnt0;

     

    % Following is to create symbols for PBCH and make a list of resource index for the signal (channel)

     

    mib_bits = lteMIB(enb);

    bch_cw = lteBCH(enb,mib_bits);

     

    % Following is to create symbols for PSS and make a list of resource index for the signal

     

    pss = ltePSS(enb);

    pss_arrayIndex = 0:length(pss)-1;

    pss_sym_ind = ltePSSIndices(enb,0,{'1based','re'});

     

    % Following is to create symbols for SSS and make a list of resource index for the signal

     

    sss = lteSSS(enb);

    sss_arrayIndex = 0:length(sss)-1;

    sss_sym_ind = lteSSSIndices(enb,0,{'1based','re'});

     

    % Following is to create symbols for PCFICH and make a list of resource index for the signal

     

    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'});

     

    % Following is to create symbols for PHICH and make a list of resource index for the signal

     

    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'});

     

    % Following is to create symbols for PBCH and make a list of resource index for the signal (channel)

     

    pbch_sym = ltePBCH(enb,bch_cw);

    pbch_sym_arrayIndex = 0:length(pbch_sym)-1;

    pbch_sym_ind = ltePBCHIndices(enb,{'1based','re'});

     

    % Following part is filling the resource grid with each of the signal.. but if you see carefully I didn't fill this

    % with real symbol number, I just filled it with a constant that I arbitrarily set. This is just for visualization..

    % just to allocate constant/outstanding color for each signal. When you  use this resource grid for real

    % transmission (not for visualization), fill the resourceGrid with real symbol value you generated above.

     

    pss_scale = 0.2;

    sss_scale = 0.4;

    phich_scale = 0.7;

    pcfich_scale = 0.5;

    pbch_scale = 0.7;

    pdcch_scale = 0.9;

    pdsch_scale = 0.6;

     

    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;

     

    % Following is for extracting Resource Elements by each symbol. Since there is no specific function to extract REs

    % for each symbol, I would generate RE indices for a specific symbol and extract REs of the indices using

    % lteExtractResources() function.

    % (enb.NDLRB*12) represents the total number of REs within a single OFDM Symbol. enb.NDLRB represents the total

    % number of RBs in a OFDM Symbol and 12 represents the number of REs within a single RB.

     

    symbolNo = 1;

    symbolIdxStart = symbolNo*(enb.NDLRB*12) + 1;

    symbolIdxEnd = symbolIdxStart + enb.NDLRB*12;

    symbolIdxArray = symbolIdxStart:symbolIdxEnd;

    symbolReArray = lteExtractResources(symbolIdxArray,resourceGrid);

     

    % Following is to plot the extracted symbol. Left side plot shows the constellation of all REs in the symbol

    % Right side plot shows the data (IQ data, complex number) along the extracted array index.

    % again the resulting graph here is intentionally distorted a little to give you the distinction among each channels.

    % the signal amplitude in real situation would be much more evenly distributed (less distiction among channels)

    % than the one you see here.

     

    subplot(1,3,1);

    plot(real(symbolReArray ),imag(symbolReArray),'ro','MarkerFaceColor',[1 0 0]);

    axis([-1 1 -1 1]);

     

    subplot(1,3,[2 3]);

    stem(abs(symbolReArray));

    axis([1 length(symbolIdxArray) 0 1]);

The code builds every channel of subframe 0 first. That means the CRS, PSS, SSS, PBCH, PCFICH, PHICH, PDCCH and a PDSCH on RB 0 to 3. Each channel is scaled by its own constant, from pss_scale = 0.2 to pdcch_scale = 0.9. The scaling is only for the plot: it gives each channel its own height, so the channels can be told apart by amplitude.

The extraction relies on the column-major layout of the grid. With 6 RB, one OFDM symbol is 6 x 12 = 72 REs, so symbol n starts at the 1-based linear index n x 72 + 1. The function lteExtractResources then returns the REs at those indices. Note that symbolIdxEnd = symbolIdxStart + enb.NDLRB*12 gives 73 indices rather than 72. The last RE of each plot is therefore the first RE of the next symbol, and the x axis of the plot runs to 73. Writing symbolIdxEnd = symbolIdxStart + enb.NDLRB*12 - 1 keeps the plot within one symbol.

The plot below shows the constellation on the left and the magnitude of each RE on the right. Stems of height 1 repeat every 6 subcarriers, and between them the REs sit at 0.5, 0.7 and 0.9.

     

      enb.NDLRB = 6;

      enb.CellRefP = 1;

      enb.NCellID = 0;

      enb.NSubframe = 0;

      symbolNo = 1;

     

    Constellation and RE magnitudes of one OFDM symbol of an LTE subframe with 6 RB

     

One OFDM symbol, 6 RB. The CRS at height 1 every 6 subcarriers, the PCFICH at 0.5, the PHICH at 0.7 and the PDCCH at 0.9. These are the contents of symbol 0, the same as the top row of the plot in the next section.

The contents show which symbol this is. The CRS of port 0 appear only in symbols 0, 4, 7 and 11, and the PCFICH and the PHICH with normal duration appear only in symbol 0. So the plot shows symbol 0, although the parameter table beside it lists symbolNo = 1. With symbolNo = 1, the code selects the second symbol of the subframe, which carries only PDCCH, as the second row of the plot in the next section shows.

  • One OFDM symbol is one column of the grid : 72 REs with 6 RB.
  • Each channel has its own height : set by the scale constants in the code.
  • The plot shows symbol 0 : CRS, PCFICH, PHICH and PDCCH.
  • symbolIdxEnd needs - 1 : otherwise the extract takes 73 REs.

SISO - Plotting All Symbols within a Subframe

One symbol shows only a slice of the subframe. This section runs the same extraction for symbols 0 to 13 and stacks the 14 results. The whole channel layout of subframe 0 can then be read one symbol at a time.

    % Since PSS is determined by each eNodeB, 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.NCellID = 0;

    enb.NSubframe = 0;

    enb.CFI = 1;

     

    PHICH_Group_Index = 0;

    PHICH_Sequence_Index = 1;

    HARQ_Indicator_Value = 0; % 0 = NACK, 1 = ACK

     

    % Now populate all the information in DCI field as you like. Understanding details of DCI is also pretty huge

    % topics. You would need separate page for DCI for the details.

     

    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;

     

    % once you defined all the detailed fields of DCI, just pass it to lteDCI() function with eNB info as follows,

    % then you will get the bit stream for the DCI.

     

    [dciMessage,dciMessageBits] = lteDCI(enb,dci);

     

    % for this step, you need to set a couple of additional parameters as shown below. C_RNTI will be XORed to CRC bits

    % PDCCHFormat will determined Aggregation Level.

    %          PDCCHFormat 0 indicate Aggregation Level 1

    %          PDCCHFormat 1 indicate Aggregation Level 2

    %          PDCCHFormat 2 indicate Aggregation Level 4

    %          PDCCHFormat 3 indicate Aggregation Level 8

     

    C_RNTI = 100;                         

    pdcchConfig.RNTI = C_RNTI;            

    pdcchConfig.PDCCHFormat = 0;          

     

    % then pass dciMessageBits and pdcchConfig to lteDCIEncode, the you would get the encoded bitstream.

     

    codedDciBits = lteDCIEncode(pdcchConfig, dciMessageBits);

     

    % If you pass the enb into ltePDCCHInfo() function, it will give you the amount of resources that can be allocated

    % for PDCCH allocation. This is not the amount of resource for only one DCI. It will give you the total/maximum

    % amount of the resources that can be allocated for PDCCH.

     

    pdcchDims = ltePDCCHInfo(enb);

     

    % With ltePDCCHSpace, you can get the list of all the possible spaces that can carry PDCCH. In this example,

    % the space were shown in the unit of bits.

     

    pdcchBits = -1*ones(pdcchDims.MTot, 1);

     

    % generate an array with the length that can accommodate all the possible PDCCH bits.

     

    candidates = ltePDCCHSpace(enb, pdcchConfig, {'bits', '1based'});

     

    % select one of the candidate bitSection and assign the codedDcitBits. You can select any candidate bit section,

    % but in this example, I selected the first candidate section.

     

    pdcchBits ( candidates(1, 1) : candidates(1, 2) ) = codedDciBits;

     

    % if pass the encodedBits into ltePDCCH(), it will generate the modulated physical layer symbols.

     

    pdcch_sym = ltePDCCH(enb, pdcchBits);

    pdcch_sym_ind = ltePDCCHIndices(enb,{'1based','re'});

    pdcch_sym_arrayIndex = 0:length(pdcch_sym)-1;

     

     

    % Now we set various parameters defining PDSCH channel. (In real transmission, you would need to create

    % a dci that is corresponding the configuration here. But in this example, I will go without defining DCI)

     

    pdsch.NTxAnts = 1;

    pdsch.NLayers = 1;

    pdsch.TxScheme = 'Port0';

    pdsch.Modulation = {'16QAM'};

    pdsch.RV = 0;

    pdsch.RNTI = C_RNTI;

     

    % Now I have to create a vector carrying the number of PRB indexes that will be used to carry this PDSCH.

    % for example, pdsch_prbs in following section would create a vector [0 1 2 3]

     

    START_RB = 0;

    N_RB = 4;

     

    pdsch_prbs = (START_RB:(START_RB+N_RB-1)).';

     

    % Now we have to generate a bit sequence which would exactly fit to the number of resource elements that are

    % allocated for PDSCH for this specific subframe. To figure out exact Resource Element information, unlike in other

    % channel processing, I would run ltePDSCHIndices() first. As you see in the following code, ltePDSCHIndices()

    % returns the information that would give you the size of transport block size in the unit of bits.

     

    [pdsch_sym_ind,pdschIndInfo] = ltePDSCHIndices(enb,pdsch,pdsch_prbs,{'1based','re'});

    codedTrBlkSize = pdschIndInfo.G;

     

    % now I would create a bit array that carries the user data. In this example, I generated randomly but in real

    % situation, this would carry your user data (e.g, image, movie, files etc)

     

    dlschTransportBlk = round(rand(1,codedTrBlkSize));

     

    % now if you pass all the information to lteDLSCH), it will generate the encoded codeword data for the transport

    % block you defined.

     

    codeword = lteDLSCH(enb,pdsch,codedTrBlkSize,dlschTransportBlk);

     

    % now if you pass the encoded data (codeword) with eNB and pdsch config to ltePDSCH(), you can generate

    % physical layer symbols for the encoded data.

     

    pdsch_sym = ltePDSCH(enb,pdsch,codeword);

    pdsch_sym_arrayIndex = 0:length(pdsch_sym)-1;

     

    % Following is to create an empty resource grid for one subframe.

     

    resourceGrid = lteDLResourceGrid(enb);

     

    % Following is to create symbols for Cell Specific Reference Signal and make a list of resource index for the

    % reference signal.

     

    rsAnt0 = lteCellRS(enb,0);

    indAnt0 = lteCellRSIndices(enb,0);

    resourceGrid(indAnt0) = rsAnt0;

     

    % Following is to create symbols for PBCH and make a list of resource index for the signal (channel)

     

    mib_bits = lteMIB(enb);

    bch_cw = lteBCH(enb,mib_bits);

     

    % Following is to create symbols for PSS and make a list of resource index for the signal

     

    pss = ltePSS(enb);

    pss_arrayIndex = 0:length(pss)-1;

    pss_sym_ind = ltePSSIndices(enb,0,{'1based','re'});

     

    % Following is to create symbols for SSS and make a list of resource index for the signal

     

    sss = lteSSS(enb);

    sss_arrayIndex = 0:length(sss)-1;

    sss_sym_ind = lteSSSIndices(enb,0,{'1based','re'});

     

    % Following is to create symbols for PCFICH and make a list of resource index for the signal

     

    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'});

     

    % Following is to create symbols for PHICH and make a list of resource index for the signal

     

    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'});

     

    % Following is to create symbols for PBCH and make a list of resource index for the signal (channel)

     

    pbch_sym = ltePBCH(enb,bch_cw);

    pbch_sym_arrayIndex = 0:length(pbch_sym)-1;

    pbch_sym_ind = ltePBCHIndices(enb,{'1based','re'});

     

    % Following part is filling the resource grid with each of the signal.. but if you see carefully I didn't fill this

    % with real symbol number, I just filled it with a constant that I arbitrarily set. This is just for visualization..

    % just to allocate constant/outstanding color for each signal. When you  use this resource grid for real

    % transmission (not for visualization), fill the resourceGrid with real symbol value you generated above.

     

    pss_scale = 0.2;

    sss_scale = 0.4;

    phich_scale = 0.7;

    pcfich_scale = 0.5;

    pbch_scale = 0.7;

    pdcch_scale = 0.9;

    pdsch_scale = 0.6;

     

    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;

     

    % Following is to plot the all 14 symbols within a subframe separately. If you see the code, this is exactly same as

    % the previous example. The only difference is the for loop around the plot routine.

    for symbolNo = 0:13

      symbolIdxStart = symbolNo*(enb.NDLRB*12) + 1;

      symbolIdxEnd = symbolIdxStart + enb.NDLRB*12;

      symbolIdxArray = symbolIdxStart:symbolIdxEnd;

      symbolReArray = lteExtractResources(symbolIdxArray,resourceGrid);

       

      subplot(14,10,(symbolNo*10)+ 1);

      plot(real(symbolReArray ),imag(symbolReArray),'ro','MarkerFaceColor',[1 0 0],'MarkerSize',2);

      axis([-1 1 -1 1]);

      set(gca,'xticklabel',[]); set(gca,'yticklabel',[]); set(gca,'xtick',[]); set(gca,'ytick',[]);

       

      subplot(14,10,[((symbolNo*10)+2):((symbolNo*10)+10)]);

      stem(abs(symbolReArray));

      axis([1 length(symbolIdxArray) 0 1]);

      set(gca,'xticklabel',[]); set(gca,'yticklabel',[]); set(gca,'xtick',[]); set(gca,'ytick',[]);

    end;

The loop draws each symbol in its own row of a 14 by 10 subplot grid. The first column holds the constellation, and the remaining nine columns hold the magnitude of each RE. Row 0 is at the top, so the rows follow the symbols of the subframe from top to bottom.

     

      enb.NDLRB = 6;

      enb.CellRefP = 1;

      enb.NCellID = 0;

      enb.NSubframe = 0;

     

    Constellation and RE magnitudes of all 14 OFDM symbols of LTE subframe 0 with 6 RB

     

The 14 OFDM symbols of subframe 0 with 6 RB, symbol 0 at the top. The control region takes symbols 0 and 1, and the SSS and PSS take symbols 5 and 6. The PBCH takes symbols 7 to 10, and the PDSCH the first 48 subcarriers of the other symbols.

The control region takes two symbols, although the code sets CFI = 1. 36.211 v19.3.0 Table 6.7-1 gives CFI + 1 symbols for PDCCH when the carrier has 10 RB or fewer, so CFI 1 means 2 symbols at 6 RB. Symbol 1 therefore carries only PDCCH. The code maps one DCI at aggregation level 1, which is one CCE of 36 REs. The rest of pdcchBits is -1, and those REs stay at zero in the plot.

The table below lists what each row of the plot carries. The PDSCH starts at symbol 2 and takes RB 0 to 3, which are the first 48 subcarriers. At 6 RB, the PSS, SSS and PBCH cover the whole carrier, so the PDSCH is absent from symbols 5 to 10.

 

Symbol

Channels

Height in the plot

0

CRS, PCFICH, PHICH, PDCCH

1, 0.5, 0.7, 0.9

1

PDCCH

0.9

2, 3

PDSCH on the first 48 subcarriers

0.6 x 16QAM amplitude

4

CRS, PDSCH

1, 0.6 x 16QAM amplitude

5

SSS on the central 62 subcarriers

0.4

6

PSS on the central 62 subcarriers

0.2

7

CRS, PBCH

1, 0.7

8, 9, 10

PBCH

0.7

11

CRS, PDSCH

1, 0.6 x 16QAM amplitude

12, 13

PDSCH on the first 48 subcarriers

0.6 x 16QAM amplitude

 

Symbols 7 and 8 have gaps in the PBCH, although the cell uses only port 0. 36.211 clause 6.6.4 maps the PBCH around the CRS of all four ports, whatever the actual number of ports. So symbol 7 leaves the REs of port 1 empty, and symbol 8 leaves those of ports 2 and 3 empty. That gives 288 - 48 = 240 PBCH REs, which is why the code takes pbch_sym(1:length(pbch_sym_ind)). The PSS and PBCH pages show those channels on their own.

The PDSCH count follows from the same table. Six symbols carry PDSCH on 48 subcarriers, which gives 288 REs, and the CRS in symbols 4 and 11 take 8 REs each. So pdschIndInfo.G is 272 x 4 = 1088 bits with 16QAM.

  • CFI 1 gives 2 control symbols at 6 RB : 36.211 Table 6.7-1.
  • SSS in symbol 5, PSS in symbol 6 : central 62 subcarriers.
  • PBCH in symbols 7 to 10 : gaps left for the CRS of four ports.
  • PDSCH on RB 0 to 3 : symbols 2 to 4 and 11 to 13, 272 REs.

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 - clauses 6.2, 6.6.4, 6.10.1.2 and 6.11, and Table 6.7-1: resource grid, PBCH, CRS, synchronization signals and PDCCH symbols