TDL Channel
This notebook shows how to use a TDL channel in time and frequency domains.
[1]:
import numpy as np
import scipy.io
import time
from neoradium import Carrier, Modem, TdlChannel, Grid, random
from neoradium.utils import getNmse
[2]:
# Create a valid random grid
random.setSeed(123) # Make results reproducible
carrier = Carrier(startRb=0, numRbs=25, spacing=15) # Carrier 25 Resource Blocks, 15KHz subcarrier spacing
bwp = carrier.curBwp # The only bandwidth part in the carrier
txGrid = bwp.createGrid(numPlanes=8) # Create an empty resource grid
stats = txGrid.getStats() # Get statistics about the grid
modem = Modem("16QAM") # Using 16QAM modulation
numRandomBits = stats['UNASSIGNED']*modem.qm # Total number of bits available in the resource grid
bits = random.bits(numRandomBits) # Create random bits
symbols = modem.modulate(bits) # Modulate the bits to get symbols
indexes = txGrid.getReIndexes("UNASSIGNED") # Indexes of the "UNASSIGNED" resources
txGrid[indexes] = symbols # Put symbols in the resource grid
txWaveform = txGrid.ofdmModulate() # OFDM-Modulate the resource grid to get a waveform
print("Shape of Resource Grid:",txGrid.shape)
print("Shape of Waveform: ",txWaveform.shape)
Shape of Resource Grid: (8, 14, 300)
Shape of Waveform: (8, 30720)
[3]:
# Create a TDL-D channel model with 4GHz carrier frequency, and 50Hz doppler shift
channel = TdlChannel(bwp, 'D', carrierFreq=4e9, dopplerShift=50,
txAntennaCount=8, rxAntennaCount=2, mimoCorrelation='Medium')
print(channel)
TDL-D Channel Properties:
carrierFreq: 4 GHz
normalizeGains: True
normalizeOutput: True
txDir: Downlink
filterLen: 16 samples
delayQuantSize: 64
stopBandAtten: 80 db
dopplerShift: 50 Hz
coherenceTime: 8.463 milliseconds
delaySpread: 30 ns
pathDelays (ns): 0.0000 1.0500 18.360 40.890 42.150 54.120 77.880 53.250 121.26 238.11
282.72 291.24 375.75
pathPowers (db): -0.001 -18.80 -21.00 -22.80 -17.90 -20.10 -21.90 -22.90 -27.80 -23.60
-24.80 -30.00 -27.70
hasLOS: True
kFactorLos (db): 13.300
rxAntennaCount: 2
txAntennaCount: 8
mimoCorrelation: Medium
polarization: CoPolar
sosType: GMEDS1
sosNumSins: 32
[4]:
# Apply the channel in Frequency Domain:
t0 =time.time()
channelMatrix = channel.getChannelMatrix()
rxGridF = txGrid.applyChannel(channelMatrix)
t1 =time.time()
print("Time to apply channel in Freq. Domain:", t1-t0)
Time to apply channel in Freq. Domain: 0.004817008972167969
[5]:
# Applying the channel in time domain and demodulate to get a received resource grid (rxGrid)
t0 =time.time()
maxDelay = channel.getMaxDelay() # Calculate the channel's max delay
paddedTxWaveform = txWaveform.pad(maxDelay) # Pad the waveform with zeros
rxWaveform = channel.applyToSignal(paddedTxWaveform) # Apply the channel to the waveform
offset = channel.getTimingOffset() # Get the timing offset for synchronization
syncedWaveform = rxWaveform.sync(offset) # Synchronization
rxGridT = Grid.ofdmDemodulate(bwp, syncedWaveform) # OFDM-demodulation
t1 =time.time()
print("Time to apply channel in Time Domain:", t1-t0)
print("NMSE between the rxGrid in Time and Freq. domains: ", getNmse(rxGridT.grid,rxGridF.grid))
Time to apply channel in Time Domain: 0.09486007690429688
NMSE between the rxGrid in Time and Freq. domains: 6.26924445685763e-17
[ ]: