CSI Compression and Reconstruction using CSINet for TDD Massive MIMO 5G Networks

Import Libraries

Import Python Libraries

[1]:
# %matplotlib widget
import matplotlib.pyplot as plt
import matplotlib as mpl

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

import numpy as np

# from IPython.display import display, HTML
# display(HTML("<style>.container { width:80% !important; }</style>"))

Import 5G Toolkit Libraries

[2]:
from csiNet import CSINet

import sys
sys.path.append("../../")

from toolkit5G.PhysicalChannels.PDSCH import ComputeTransportBlockSize
from toolkit5G.PhysicalChannels       import PDSCHLowerPhy, PDSCHUpperPhy, PDSCHDecoderLowerPhy, PDSCHDecoderUpperPhy
from toolkit5G.ChannelModels          import AntennaArrays, SimulationLayout, ParameterGenerator, ChannelGenerator
from toolkit5G.Configurations         import PDSCHLowerPhyConfiguration, PDSCHUpperPhyConfiguration
from toolkit5G.ChannelProcessing      import AddNoise, ApplyChannel
from toolkit5G.SymbolMapping          import Mapper, Demapper

Simulation Parameters

[3]:
# Carrier Frequency
carrierFrequency = 3.6*10**9
delaySpread      = 100*(10**-9)
numBatches       = 200       # Number of batches considered for simulation
scs              = 30*10**3  # Subcarrier Spacing for simulation
numBSs           = 1 # Number of BSs considered for simulation
# Number of UEs considered for simulation
numUEs           = numBatches # For now we are assuming that the numbatches are captured via numUEs
numRB            = 85 # Number of Resource mapping considered for simulation | # 1 RB = 12 subcarrier
slotNumber       = int(np.random.randint(0,2**(scs/15000)*10)) # Index of the slot considered for simulation
terrain          = "CDL-A" # Terrain
txAntStruture    = np.array([1,1,32,1,1]) # Tx Antenna Structure
rxAntStruture    = np.array([1,1,4,1,1]) # Tx Antenna Structure
Nfft             = 1024 # FFTSize

print("************ Simulation Parameters *************")
print()
print("     numBatches: "+str(numBatches))
print("          numRB: "+str(numRB))
print("       fft Size: "+str(Nfft))
print("         numBSs: "+str(numBSs))
print("         numUEs: "+str(numUEs))
print("            scs: "+str(scs))
print("     slotNumber: "+str(slotNumber))
print("        terrain: "+str(terrain))
print("Tx Ant Struture: "+str(txAntStruture))
print("Rx Ant Struture: "+str(rxAntStruture))
print()
print("********************************************")
************ Simulation Parameters *************

     numBatches: 200
          numRB: 85
       fft Size: 1024
         numBSs: 1
         numUEs: 200
            scs: 30000
     slotNumber: 0
        terrain: CDL-A
Tx Ant Struture: [ 1  1 32  1  1]
Rx Ant Struture: [1 1 4 1 1]

********************************************

Wireless Channel Generation: CDL-A

[4]:
# Antenna Array at UE side
# assuming antenna element type to be "OMNI"
# with 2 panel and 2 single polarized antenna element per panel.
ueAntArray = AntennaArrays(antennaType = "OMNI",  centerFrequency = carrierFrequency,
                           arrayStructure  = rxAntStruture)
ueAntArray()

# # Radiation Pattern of Rx antenna element
# ueAntArray.displayAntennaRadiationPattern()


# Antenna Array at BS side
# assuming antenna element type to be "3GPP_38.901", a parabolic antenna
# with 4 panel and 4 single polarized antenna element per panel.
bsAntArray = AntennaArrays(antennaType = "3GPP_38.901", centerFrequency = carrierFrequency,
                           arrayStructure  = txAntStruture)
bsAntArray()

# # Radiation Pattern of Tx antenna element
# bsAntArray[0].displayAntennaRadiationPattern()

# Layout Parameters
isd                  = 100         # inter site distance
minDist              = 10          # min distance between each UE and BS
ueHt                 = 1.5         # UE height
bsHt                 = 25          # BS height
bslayoutType         = "Hexagonal" # BS layout type
ueDropType           = "Hexagonal" # UE drop type
htDist               = "equal"     # UE height distribution
ueDist               = "equal"     # UE Distribution per site
nSectorsPerSite      = 1           # number of sectors per site
maxNumFloors         = 1           # Max number of floors in an indoor object
minNumFloors         = 1           # Min number of floors in an indoor object
heightOfRoom         = 3           # height of room or ceiling in meters
indoorUEfract        = 0.5         # Fraction of UEs located indoor
lengthOfIndoorObject = 3           # length of indoor object typically having rectangular geometry
widthOfIndoorObject  = 3           # width of indoor object
# forceLOS             = True       # boolen flag if true forces every link to be in LOS state
forceLOS             = False       # boolen flag if true forces every link to be in LOS state

# simulation layout object
simLayoutObj = SimulationLayout(numOfBS = numBSs,
                                numOfUE = numUEs,
                                heightOfBS = bsHt,
                                heightOfUE = ueHt,
                                ISD = isd,
                                layoutType = bslayoutType,
                                ueDropMethod = ueDropType,
                                UEdistibution = ueDist,
                                UEheightDistribution = htDist,
                                numOfSectorsPerSite = nSectorsPerSite,
                                ueRoute = None)

simLayoutObj(terrain = terrain,
             carrierFreq = carrierFrequency,
             ueAntennaArray = ueAntArray,
             bsAntennaArray = bsAntArray,
             indoorUEfraction = indoorUEfract,
             lengthOfIndoorObject = lengthOfIndoorObject,
             widthOfIndoorObject = widthOfIndoorObject,
             forceLOS = forceLOS)

# displaying the topology of simulation layout
fig, ax = simLayoutObj.display2DTopology()

paramGen = simLayoutObj.getParameterGenerator(delaySpread = delaySpread)

# paramGen.displayClusters((0,0,0), rayIndex = 0)
channel = paramGen.getChannel()
Hf      = channel.ofdm(scs, Nfft, normalizeChannel = True)

Nt        = bsAntArray.numAntennas # Number of BS Antennas
Nr        = ueAntArray.numAntennas

print("             Number of BSs: "+str(numBSs))
print("          Shape of Channel: "+str(Hf.shape))
print("*****************************************************")
print()
../../../_images/api_Projects_Project3_CSI_Compression_and_Reconstruction_using_CSINet_for_TDD_Massive_MIMO_5G_Networks_7_0.png
             Number of BSs: 1
          Shape of Channel: (1, 1, 1, 200, 1024, 4, 32)
*****************************************************

Reconstrunction Performance of CSI-Net

[5]:
numSubcarrier = 32
codewordSize  = 512

H      = Hf[0,0,0,...,0,:].transpose(0,2,1)
csinet = CSINet()
model  = csinet(Nt, numSubcarrier, codewordSize)
csinet.loadModel()
Hprep  = csinet.preprocess(H)

Hrec   = csinet.predict(Hprep)

Hest   = csinet.postprocess(Hprep, Nfft)
7/7 [==============================] - 0s 7ms/step
[6]:
numChannels = 5
fig, ax = plt.subplots(2,numChannels, figsize = (12, 5))

idx = np.random.choice(np.arange(numBatches), size=numChannels, replace = False)
print(idx)
for n in range(numChannels):
    ax[0,n].imshow(np.abs(Hprep[idx[n],0])**2 + np.abs(Hprep[idx[n],1])**2, cmap = "Greys", aspect = "auto")
    ax[1,n].imshow(np.abs( Hrec[idx[n],0])**2 + np.abs( Hrec[idx[n],1])**2, cmap = "Greys", aspect = "auto")

plt.show()
[153 134 179 124  21]
../../../_images/api_Projects_Project3_CSI_Compression_and_Reconstruction_using_CSINet_for_TDD_Massive_MIMO_5G_Networks_10_1.png
[7]:
print("NMSE: "+str(np.sqrt(np.mean(np.abs(Hest-H)**2/(np.abs(H))**2))))
NMSE: 0.20250736648608653

PDSCH Parameters

[8]:
########################################## PDSCH Lower Physical Layer Parameters #########################################
pdschLowerPhyConfig    = PDSCHLowerPhyConfiguration(rank = 1, startSymbol=2, numSymbols=12, pdschMappingType = "PDSCH-mapping-type-A",
                                                    maxLength = "len1", dmrsAdditionalPosition = "pos0", l0 = 0,
                                                    configurationType = "Configuration-type-1")
pdschMappingType       = pdschLowerPhyConfig.pdschMappingType   # "PDSCH mapping type A" or "PDSCH mapping type B"
maxLength              = pdschLowerPhyConfig.maxLength
startSymbol            = pdschLowerPhyConfig.startSymbol
numSymbols             = pdschLowerPhyConfig.numSymbols
betaDMRS               = pdschLowerPhyConfig.betaDMRS
configurationType      = pdschLowerPhyConfig.configurationType   # "Configuration-type-1" or "Configuration-type-2"
dmrsTypeAPosition      = pdschLowerPhyConfig.dmrsTypeAPosition                                   # "pos2" or "pos3"
dmrsAdditionalPosition = pdschLowerPhyConfig.dmrsAdditionalPosition  # "pos2" or "pos3"
ld                     = pdschLowerPhyConfig.ld
l0                     = pdschLowerPhyConfig.l0
l1                     = pdschLowerPhyConfig.l1
rank                   = pdschLowerPhyConfig.rank
scramblingID           = pdschLowerPhyConfig.scramblingID
nSCID                  = pdschLowerPhyConfig.nSCID

mcsIndex               = 3
mcsTable               = "pdschTable1"

########################################## PDSCH Parameters #########################################
pdschUpperPhyConfig    = PDSCHUpperPhyConfiguration(pdschMappingType = pdschMappingType, configurationType = configurationType,
                                                    dmrsTypeAPosition = dmrsTypeAPosition, maxLength = maxLength, mcsIndex = mcsIndex,
                                                    mcsTable = mcsTable, dmrsAdditionalPosition = dmrsAdditionalPosition, l0 = l0,
                                                    ld = ld, l1 = l1, startSymbol = startSymbol, numSymbols = numSymbols, rank = rank,
                                                    numRB = numRB)

numTBs                 = pdschUpperPhyConfig.numTBs
numRB                  = pdschUpperPhyConfig.numRB
tbLen1                 = pdschUpperPhyConfig.tbLen1

codeRate               = pdschUpperPhyConfig.codeRate
modOrder               = pdschUpperPhyConfig.modOrder
mcsIndex               = pdschUpperPhyConfig.mcsIndex
mcsTable               = pdschUpperPhyConfig.mcsTable
numlayers              = pdschUpperPhyConfig.numlayers
scalingField           = pdschUpperPhyConfig.scalingField
additionalOverhead     = pdschUpperPhyConfig.additionalOverhead
dmrsREs                = pdschUpperPhyConfig.dmrsREs
additionalOverhead     = pdschUpperPhyConfig.additionalOverhead

numTargetBits1         = pdschUpperPhyConfig.numTargetBits1
if(numTBs == 2):
    numTargetBits1     = pdschUpperPhyConfig.numTargetBits1
    numTargetBits2     = pdschUpperPhyConfig.numTargetBits2
    tbLen2             = pdschUpperPhyConfig.tbLen2

numTargetBits          = pdschUpperPhyConfig.numTargetBits
************ PDSCH Parameters *************

       pdschMappingType: PDSCH-mapping-type-A
            startSymbol: 2
             numSymbols: 12
               betaDMRS: 1
                   rank: 1
      configurationType: Configuration-type-1
              maxLength: len1
      dmrsTypeAPosition: pos2
 dmrsAdditionalPosition: pos0
           Duration, ld: 12
       Start symbol, l0: 0
     Start symbol-1, l1: 11
          num of Layers: 1

********************************************
********************************************
          tbsize-1: 5768

            numTBs: 1
            numCBs: 2
         numLayers: 1 | LayerperTB: [1 0]
             numRB: 85
          coderate: 0.2451171875
          modOrder: 2
additionalOverhead: 0
numberTargetBits: 23460
********************************************

PDSCH: Transmitter

[9]:

pdschUpperPhy = PDSCHUpperPhy(symbolsPerSlot = numSymbols, numRB = numRB, mcsIndex = mcsIndex, numlayers = numlayers, scalingField = scalingField, additionalOverhead = additionalOverhead, dmrsREs = dmrsREs, numTBs=numTBs, pdschTable = mcsTable, verbose = False) codeword = pdschUpperPhy(tblock = [None, None], rvid = [0, 0], enableLBRM = [False, False], numBatch = numBatches, numBSs = numBSs) rnti = np.random.randint(65536, size=numBSs*numBatches) nID = np.random.randint(1024, size=numBSs*numBatches) bits2 = codeword[1] if numTBs == 2 else None pdschLowerPhyChain = PDSCHLowerPhy(pdschMappingType, configurationType, dmrsTypeAPosition, maxLength, dmrsAdditionalPosition, l0, ld, l1) resourceGrid = pdschLowerPhyChain(codeword[0], numRB, rank, slotNumber, scramblingID, nSCID, rnti, nID, modOrder, startSymbol, bits2 = bits2) ## Load the resource Grid into the transmision Grid txGrid = np.zeros(resourceGrid.shape[0:-1]+(Nfft,), dtype= np.complex64) bwpOffset = np.random.randint(Nfft-numRB*12) txGrid[...,bwpOffset:bwpOffset+numRB*12] = resourceGrid fig, ax = pdschLowerPhyChain.displayDMRSGrid() pdschLowerPhyChain.displayResourceGrid()

../../../_images/api_Projects_Project3_CSI_Compression_and_Reconstruction_using_CSINet_for_TDD_Massive_MIMO_5G_Networks_15_1.png
[9]:
(<Figure size 640x480 with 1 Axes>,
 <Axes: xlabel='OFDM Symbol-Index', ylabel='Subcarrier-Index'>)
../../../_images/api_Projects_Project3_CSI_Compression_and_Reconstruction_using_CSINet_for_TDD_Massive_MIMO_5G_Networks_15_3.png
[10]:
fig, ax = plt.subplots(1,2)

ax[0].plot(np.abs(Hf[0,0,0,0,:,0,5]))
ax[0].grid()
ax[1].plot(np.abs(Hf[0,0,0,0,:,0,3]))
ax[1].grid()
plt.show()
../../../_images/api_Projects_Project3_CSI_Compression_and_Reconstruction_using_CSINet_for_TDD_Massive_MIMO_5G_Networks_16_0.png

SVD Based Beamforming: Perfect CSI

[11]:
# Digital Beamforming
[U, S, Vh] = np.linalg.svd(Hf)
precoder   = np.conj(Vh.transpose(3,0,1,2,4,6,5)[...,0:rank])
combiner   = np.conj((U*(1/S[...,np.newaxis,:].repeat(S.shape[-1], axis = -2)))[...,0:rank].transpose(3,0,1,2,4,6,5))
xBeam      = (precoder@txGrid.transpose(0,1,3,4,2)[:,np.newaxis,...,np.newaxis])[...,0]

print("************ Beamforming Parameters *************")
print()
print("    Precoder Shape: "+str(precoder.shape))
print("    Combiner Shape: "+str(combiner.shape))
print("     Channel Shape: "+str(Hf.shape))
print("Eigen Matrix Shape: "+str(S.shape))
print("Beamformed Grid sh: "+str(xBeam.shape))
print()
print("********************************************")
************ Beamforming Parameters *************

    Precoder Shape: (200, 1, 1, 1, 1024, 32, 1)
    Combiner Shape: (200, 1, 1, 1, 1024, 1, 4)
     Channel Shape: (1, 1, 1, 200, 1024, 4, 32)
Eigen Matrix Shape: (1, 1, 1, 200, 1024, 4)
Beamformed Grid sh: (200, 1, 1, 14, 1024, 32)

********************************************

Pass through Channel

[12]:
# Channel Dimensions: numBatches, numFrequencies, numSymbols(numSnapshots), numBSs, numUEs, numSamples/numFFTpoints, numRxAntennas, numTxAntennas
# Tx-Grid Dimensions: numBatches, numFrequencies, numSymbols(numSnapshots), numBSs,         numSamples/numFFTpoints,                numTxAntennas
# Rx-Grid Dimensions: numBatches, numFrequencies, numSymbols(numSnapshots),   --    numUEs, numSamples/numFFTpoints, numRxAntennas

ptc = ApplyChannel(isFrequencyDomain = True, enableInterTxInterference = True, memoryConsumptionLevel = 0)
y   = ptc(Hf[np.newaxis].transpose(4,0,1,2,3,5,6,7), xBeam.transpose(0,1,3,2,4,5))

print("************ Channel Parameters *************")
print()
print("      Channel Shape: "+str(Hf.shape))
print("Received Grid shape: "+str(y.shape))
print(" Beamformed Grid sh: "+str(xBeam.shape))
print()
print("********************************************")
************ Channel Parameters *************

      Channel Shape: (1, 1, 1, 200, 1024, 4, 32)
Received Grid shape: (200, 1, 14, 1, 1024, 4)
 Beamformed Grid sh: (200, 1, 1, 14, 1024, 32)

********************************************

SVD Based Beamforming: CSI Reconstructed using CSINet

[14]:
# Digital Beamforming

shape      = Hf[0,0,0].shape
Hest = np.zeros((shape[0], shape[2], shape[3], shape[1]), dtype = np.complex64)

for nr in range(Nr):
    H          = Hf[0,0,0,...,nr,:].transpose(0,2,1)
    Hprep      = csinet.preprocess(H)
    Hrec       = csinet.predict(Hprep)
    Hest[:,nr] = csinet.postprocess(Hprep, Nfft)

[U, S, Vh] = np.linalg.svd(Hest.transpose(0,3,1,2)[np.newaxis, np.newaxis,np.newaxis])
precoder   = np.conj(Vh.transpose(3,0,1,2,4,6,5)[...,0:rank])
combiner   = np.conj((U*(1/S[...,np.newaxis,:].repeat(S.shape[-1], axis = -2)))[...,0:rank].transpose(3,0,1,2,4,6,5))
xBeam      = (precoder@txGrid.transpose(0,1,3,4,2)[:,np.newaxis,...,np.newaxis])[...,0]

print("************ Beamforming Parameters *************")
print()
print("    Precoder Shape: "+str(precoder.shape))
print("    Combiner Shape: "+str(combiner.shape))
print("     Channel Shape: "+str(Hf.shape))
print("Eigen Matrix Shape: "+str(S.shape))
print("Beamformed Grid sh: "+str(xBeam.shape))
print()
print("********************************************")
7/7 [==============================] - 0s 6ms/step
7/7 [==============================] - 0s 6ms/step
7/7 [==============================] - 0s 7ms/step
7/7 [==============================] - 0s 6ms/step
************ Beamforming Parameters *************

    Precoder Shape: (200, 1, 1, 1, 1024, 32, 1)
    Combiner Shape: (200, 1, 1, 1, 1024, 1, 4)
     Channel Shape: (1, 1, 1, 200, 1024, 4, 32)
Eigen Matrix Shape: (1, 1, 1, 200, 1024, 4)
Beamformed Grid sh: (200, 1, 1, 14, 1024, 32)

********************************************

Pass through Wireless Channel

[15]:
# Channel Dimensions: numBatches, numFrequencies, numSymbols(numSnapshots), numBSs, numUEs, numSamples/numFFTpoints, numRxAntennas, numTxAntennas
# Tx-Grid Dimensions: numBatches, numFrequencies, numSymbols(numSnapshots), numBSs,         numSamples/numFFTpoints,                numTxAntennas
# Rx-Grid Dimensions: numBatches, numFrequencies, numSymbols(numSnapshots),   --    numUEs, numSamples/numFFTpoints, numRxAntennas

ptc = ApplyChannel(isFrequencyDomain = True, enableInterTxInterference = True, memoryConsumptionLevel = 0)
y   = ptc(Hf[np.newaxis].transpose(4,0,1,2,3,5,6,7), xBeam.transpose(0,1,3,2,4,5))

print("************ Channel Parameters *************")
print()
print("      Channel Shape: "+str(Hf.shape))
print("Received Grid shape: "+str(y.shape))
print(" Beamformed Grid sh: "+str(xBeam.shape))
print()
print("********************************************")
************ Channel Parameters *************

      Channel Shape: (1, 1, 1, 200, 1024, 4, 32)
Received Grid shape: (200, 1, 14, 1, 1024, 4)
 Beamformed Grid sh: (200, 1, 1, 14, 1024, 32)

********************************************

Performance Evaluations

Throughput Evaluations

[18]:
fig, ax = plt.subplots()

ax.semilogy(SNRdB,  throughput,  "b",   marker = "*", lw = 3, mec = "k", mfc = "r", ms = 12, label="Throughput [Perfect-CSI]")
ax.semilogy(SNRdB2, throughput2, "--r", marker = "o", lw = 3, mec = "w", mfc = "r", ms = 9, label="Throughput [CSINet]")

ax.set_xlabel("Signal to Noise Ratio (dB)")
ax.set_ylabel("Throughput (bits per second)")
ax.set_title("Data-rate Evaluation: SNR (dB) vs Throughput", fontsize = 16)
ax.legend(loc="best")

ax.set_xticks(SNRdB2, minor=False)
ax.xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter('%.2f'))
ytck = 10**(np.arange(2, 9)).repeat(10)*np.tile(np.arange(1, 11), [7])
ax.set_yticks(ytck, minor=True)
ax.set_yticks(10**(np.arange(2, 8)), minor=False)
ax.set_ylim([10**2, 10**8])
# ax.set_xlim([0.999*SNRdB[0], 1.05*SNRdB[-1]])
ax.grid(which = 'minor', alpha = 0.5, linestyle = '--')
ax.grid(which = 'major', alpha = 0.65, color = "k")

plt.show()
../../../_images/api_Projects_Project3_CSI_Compression_and_Reconstruction_using_CSINet_for_TDD_Massive_MIMO_5G_Networks_31_0.png

BLER Evaluations

[19]:
fig, ax = plt.subplots()

ax.semilogy(SNRdB,  bler,    "g", marker = "X", lw = 3, mec = "k", mfc = "w", ms = 9, label="BLER [Perfect-CSI]")
ax.semilogy(SNRdB2, bler2, "--b", marker = "o", lw = 3, mec = "w", mfc = "r", ms = 9, label="BLER [CSI-Net]")

ax.legend(loc="best")
ax.set_xlabel("Signal to Noise Ratio (dB)")
ax.set_ylabel("Block (Bit) Error Rate")
ax.set_title("Reliability Evaluation: SNR (dB) vs B(L)ER", fontsize = 16)

# ax.set_xticks(SNRdB1)
ax.xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter('%.2f'))
ytck = (0.1**(np.arange(1, 10))).repeat(9)*np.tile(np.arange(10, 1,-1), [9])
ytck = np.concatenate([[1],ytck])
ax.set_yticks(ytck, minor=True)
ax.set_yticks(0.1**(np.arange(0, 9)), minor=False)
ax.set_ylim([0.5*10**-5,1.2])

ax.grid(which = 'minor', alpha = 0.5, linestyle = '--')
ax.grid(which = 'major', alpha = 0.65, color = "k")

plt.show()
../../../_images/api_Projects_Project3_CSI_Compression_and_Reconstruction_using_CSINet_for_TDD_Massive_MIMO_5G_Networks_33_0.png

References

  1. Deep Learning for Massive MIMO CSI Feedback

[ ]: