Comparing the CDL Channel results with MATLAB
Compare the results of this notebook with the MATLAB file CDLTest.mlx in the MatlabFiles directory.
The “.mat” files in the MatlabFiles directory were created by MATLAB running the CDLTest.mlx file. If you want to recreate these files, follow the instructions in the MATLAB file. Here is the execution results of this code in MATLAB.
[1]:
import numpy as np
import scipy.io
from neoradium import Carrier, CdlChannel, AntennaPanel, random, Waveform
from neoradium.utils import getNmse
matlabFilesPath = "./MatlabFiles"
CDL Channel Model
Now we want to create a CDL Channel object (CdlChannel) and apply it to the time-domain waveform.
Note 1: Since CDL is a statistical model, there is inherent randomness in how the phases are initialized and how rays are coupled. The
getMatlabRandomInit helper function can be used to create the same random initial phases and ray couplings that are generated by the MATLAB code.Note 2: NeoRadium’s implementation of FIR filters used by the CDL channel is slightly different from MATLAB’s. To compensate for this
difference, we need to modify the
stopBandAtten parameter.Note 3: MATLAB uses a different order for the antenna elements in a panel from NeoRadium and the 3GPP standard. To compare the results, we set
the
matlabOrder parameter to True for both antenna panels.[2]:
carrier = Carrier(startRb=0, numRbs=25, spacing=15) # Carrier 25 Resource Blocks, 15 kHz subcarrier spacing
bwp = carrier.curBwp # The only bandwidth part in the carrier
cdlModel = 'D'
seed = 123
phiInit, coupling = CdlChannel.getMatlabRandomInit(cdlModel, seed) # Match MATLAB random values
speedKmh = 15 # speed of UE device: 15 km/h
speed = speedKmh*1000/3600 # m/s
c = 299792458 # Speed of light
fc = 4e9 # 4 GHz
d = speed*fc/c # Doppler Shift (Hz)
# Create the channel model
channel = CdlChannel(bwp, cdlModel, delaySpread=10, carrierFreq=fc, dopplerShift=d,
initialPhases = phiInit, rayCoupling = coupling,
txAntenna = AntennaPanel([2,2], polarization="x", matlabOrder=True, polModel=2),
rxAntenna = AntennaPanel([1,1], polarization="+", matlabOrder=True, polModel=2),
txOrientation = [10, 20, 30],
rxOrientation = [180, 0, 0],
angleScaling = ([130,70,80,110], [5,11,3,3]), # Angle Scaling
stopBandAtten = 70) # Default is 80
channel.print()
CDL-D Channel Properties:
carrierFreq: 4 GHz
normalizeGains: True
normalizeOutput: True
txDir: Downlink
filterLen: 16 samples
delayQuantSize: 64
stopBandAtten: 70 dB
dopplerShift: 55.59 Hz
coherenceTime: 7.611 milliseconds
delaySpread: 10 ns
ueDirAZ: 0°, 90°
Angle Scaling:
Means: 130° 70° 80° 110°
RMS Spreads: 5° 11° 3° 3°
xPolPower: 11.00 dB
angleSpreads: 5° 8° 3° 3°
TX Antenna:
Total Elements: 8
spacing: 0.5𝜆, 0.5𝜆
shape: 2 rows x 2 columns
polarization: x
Orientation (𝛼,𝛃,𝛄): 10° 20° 30°
RX Antenna:
Total Elements: 2
spacing: 0.5𝜆, 0.5𝜆
shape: 1 rows x 1 columns
polarization: +
Orientation (𝛼,𝛃,𝛄): 180° 0° 0°
hasLOS: True
LOS Path:
Delay (ns): 0.00000
Power (dB): -0.20000
AOD (Deg): 0.0
AOA (Deg): -180.0
ZOD (Deg): 98.0
ZOA (Deg): 82.0
NLOS Paths (13):
Delays (ns): 0.000 0.350 6.120 13.63 14.05 18.04 25.96 17.75 40.42 79.37 94.24 97.08 125.2
Powers (dB): -13.5 -18.8 -21.0 -22.8 -17.9 -20.1 -21.9 -22.9 -27.8 -23.6 -24.8 -30.0 -27.7
AODs (Deg): 0 89 89 89 13 13 13 35 -64 -33 53 -132 77
AOAs (Deg): -180 89 89 89 163 163 163 -137 74 128 -120 -9 -84
ZODs (Deg): 98 86 86 86 98 98 98 98 88 91 104 80 86
ZOAs (Deg): 82 87 87 87 79 79 79 78 74 78 87 71 73
Applying the channel to a random waveform
Now we create a random waveform one subframe long (1 ms) and apply our CDL Channel to the waveform. To compare the results with MATLAB, we read the waveform from a file created by the MATLAB program CDLTest.mlx.
[3]:
# Create a random signal for 1 subframe (1 ms)
t = 0.001 # 1 subframe = 1 ms
numInputSamples = int(channel.sampleRate * t)
nr, nt = channel.nrNt # Get the number of antenna from the channel
# Load the "txWaveform" generated by the MATLAB code
txWaveform = scipy.io.loadmat(matlabFilesPath+'/txWaveform.mat')['txWaveform'].T
assert txWaveform.shape==(nt, numInputSamples)
# Check the following numbers with the MATLAB-generated numbers to make sure we are using
# the same input signal:
print("TX Waveform Data:\n", np.round(txWaveform[2:4,200:204].T,4)) # MATLAB: txWaveform(201:204,3:4)
# Use the following line instead of above line to create a random signal (The result will be
# different from MATLAB)
# txWaveform = np.random.normal(size=(numSamples, nt)) + 1j*np.random.normal(size=(numSamples, nt))
# Now apply the channel to the waveform
rxWaveform = channel.applyToSignal(txWaveform)
print("RX Waveform Data:\n", np.round(rxWaveform[1,200:204].T,4)) # MATLAB: rxWaveform(201:204,2)
# Load MATLAB results and compare with the above results
rxWaveformMatlab = scipy.io.loadmat(matlabFilesPath+'/rxWaveform.mat')['rxWaveform']
assert rxWaveformMatlab.shape==(numInputSamples, nr)
print("NMSE:", getNmse(rxWaveformMatlab.T,rxWaveform.waveform)) # NMSE between NeoRadium and MATLAB results
TX Waveform Data:
[[-1.4866-0.7976j 2.1968-0.0359j]
[ 0.0656+0.775j 0.4241+1.7407j]
[ 0.0862+0.9547j 0.4668+1.7866j]
[-0.8242+0.6706j 0.2277+1.1032j]]
RX Waveform Data:
[ 0.0126-0.0086j 0.0055+0.0029j -0.0135+0.0006j -0.0057+0.0084j]
NMSE: 5.4597016465344875e-05
[ ]: