{ "cells": [ { "cell_type": "markdown", "id": "f7b6d03e-3371-463d-ae05-7f101fed8b2d", "metadata": {}, "source": [ "# Comparing SISO CDL Channel results with Matlab\n", "Compare the results of this notebook with the Matlab file ``SisoCdl.mlx`` in the ``MatlabFiles`` directory.\n", "\n", "The \".mat\" files in the ``MatlabFiles`` directory were created by Matlab running the ``SisoCdl.mlx`` file. If you want to recreate these files, follow the instructions in the Matlab file. [Here](MatlabFiles/SisoCdl.html) is the execution results of this code in Matlab." ] }, { "cell_type": "code", "execution_count": 1, "id": "afc610f2-e675-4fd9-8eee-433d5f21f5d7", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import scipy.io\n", "\n", "from neoradium import Carrier, CdlChannel, random, Waveform\n", "from neoradium.utils import getNmse\n", "\n", "matlabFilesPath = \"./MatlabFiles\"" ] }, { "cell_type": "code", "execution_count": 2, "id": "c2dba143-3d76-42d3-a888-9e56749563a7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "CDL-C Channel Properties:\n", " carrierFreq: 4 GHz\n", " normalizeGains: True\n", " normalizeOutput: True\n", " txDir: Downlink\n", " filterLen: 16 samples\n", " delayQuantSize: 64\n", " stopBandAtten: 70 dB\n", " dopplerShift: 55.59401586635868 Hz\n", " coherenceTime: 7.611 milliseconds\n", " delaySpread: 10 ns\n", " ueDirAZ: 0.0°, 90.0°\n", " Cross Pol. Power: 7 dB\n", " angleSpreads: 2° 15° 3° 7°\n", " TX Antenna:\n", " freqRange: 0 Hz .. 100 GHz\n", " polAngle: 0°\n", " polModel: 2\n", " beamWidth: 65°,65°\n", " verticalSidelobeAttenuation: 30\n", " maxAttenuation: 30 dB\n", " mainMaxGain: 8 dBi\n", " RX Antenna:\n", " freqRange: 0 Hz .. 100 GHz\n", " polAngle: 0°\n", " polModel: 2\n", " beamWidth: 65°,65°\n", " verticalSidelobeAttenuation: 30\n", " maxAttenuation: 30 dB\n", " mainMaxGain: 8 dBi\n", " Orientation (𝛼,𝛃,𝛄): 180° 0° 0°\n", " hasLOS: False\n", " NLOS Paths (24):\n", " Delays (ns): 0.000 2.099 2.219 2.329 2.176 6.366 6.448 6.560 6.584 7.935 8.213 9.336\n", " 12.28 13.08 21.70 27.10 42.58 46.00 54.90 56.07 63.06 66.37 70.42 86.52\n", " Powers (dB): -4.40 -1.20 -3.50 -5.20 -2.50 0.000 -2.20 -3.90 -7.40 -7.10 -10.7 -11.1\n", " -5.10 -6.80 -8.70 -13.2 -13.9 -13.9 -15.8 -17.1 -16.0 -15.7 -21.6 -22.8\n", " AODs (Deg): -47 -23 -23 -23 -41 0 0 0 73 -64 80 -97 \n", " -55 -64 -78 103 99 89 -102 92 93 107 119 -124\n", " AOAs (Deg): -101 120 120 120 -128 170 170 170 55 66 -48 47 \n", " 68 -69 82 31 -16 4 -14 10 6 1 -22 34 \n", " ZODs (Deg): 97 99 99 99 101 99 99 99 105 95 106 94 \n", " 104 104 93 104 95 93 92 107 93 93 105 108 \n", " ZOAs (Deg): 88 72 72 72 70 75 75 75 67 64 71 60 \n", " 91 60 61 101 62 67 53 62 52 62 58 57 \n", "\n" ] } ], "source": [ "carrier = Carrier(startRb=0, numRbs=25, spacing=15) # Carrier 25 Resource Blocks, 15KHz subcarrier spacing\n", "bwp = carrier.curBwp # The only bandwidth part in the carrier\n", "\n", "cdlModel = 'C'\n", "seed = 123\n", "phiInit, coupling = CdlChannel.getMatlabRandomInit(cdlModel, seed) # Match Matlab random values\n", "\n", "speedKmh = 15 # speed of UE device: 15 km/h\n", "speed = speedKmh*1000/3600 # m/s\n", "c = 299792458 # Speed of light\n", "fc = 4e9 # 4 GHz\n", "d = speed*fc/c # Doppler Shift (Hz)\n", "\n", "# NOTE: Always make sure to use this antenna config in Matlab to match the standard and NeoRadium's default\n", "# cdl.TransmitAntennaArray.Size = [1 1 1 1 1]; % 1x1 antenna panel\n", "# cdl.TransmitAntennaArray.Element = '38.901'; % Make sure we are using 3GPP antennas. (Default is not 3GPP)\n", "# cdl.TransmitArrayOrientation = [0; 0; 0]; % Transmit antenna orientation bearing(α), downtilt(β), and slant(γ) angles in degrees\n", "# cdl.TransmitAntennaArray.PolarizationAngles = [0 90];\n", "\n", "# cdl.ReceiveAntennaArray.Size = [1 1 1 1 1]; % 1x1 antenna\n", "# cdl.ReceiveAntennaArray.Element = '38.901'; % Make sure we are using 3GPP antennas. (Default is not 3GPP)\n", "# cdl.ReceiveArrayOrientation = [180; 0; 0]; % Receive antenna orientation bearing(α), downtilt(β), and slant(γ) angles in degrees\n", "# cdl.ReceiveAntennaArray.PolarizationAngles = [0 90];\n", "\n", "\n", "# Create the channel model\n", "channel = CdlChannel(bwp, cdlModel, delaySpread=10, carrierFreq=fc, dopplerShift=d,\n", " initialPhases = phiInit, rayCoupling = coupling,\n", " stopBandAtten = 70) # NeoRadium default is 80; Matlab default is 70;\n", "channel.print()" ] }, { "cell_type": "code", "execution_count": 3, "id": "60e9f60c-33d7-4a35-8708-49753c1290f5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TX Waveform Data:\n", " [ 0.3957+0.3554j 0.1609-1.6695j -0.1543+0.4127j -0.484 -1.0458j]\n", "RX Waveform Data:\n", " [ 1.0979-0.9033j 0.1692-0.5916j -0.7662-0.9718j 0.1534-0.7265j]\n", "NMSE: 9.313019773677275e-05\n" ] } ], "source": [ "# Create a random signal for 1 subframe (1 ms)\n", "t = 0.001 # 1 subframe = 1 ms\n", "numInputSamples = int(channel.sampleRate * t)\n", "nr, nt = channel.nrNt # Get the number of antanna from the channel\n", "\n", "# Load the \"txWaveform\" generated by the Matlab code\n", "txWaveform = scipy.io.loadmat(matlabFilesPath+'/txWaveform.mat')['txWaveform'].T\n", "assert txWaveform.shape==(nt, numInputSamples)\n", "\n", "# Check the following numbers with the Matlabmatlab-generated numbers to make sure we are using\n", "# the same input signal:\n", "print(\"TX Waveform Data:\\n\", np.round(txWaveform[0,200:204],4)) # Matlab: txWaveform(201:204,3:4)\n", "\n", "# Use the following line instead of above line to create a random signal (The result will be \n", "# different from Matlab)\n", "# txWaveform = np.random.normal(size=(numSamples, nt)) + 1j*np.random.normal(size=(numSamples, nt))\n", "\n", "# Now apply the channel to the waveform\n", "rxWaveform = channel.applyToSignal(txWaveform) \n", "print(\"RX Waveform Data:\\n\", np.round(rxWaveform[0,200:204],4)) # Matlab: rxWaveform(201:204,2)\n", "\n", "# Load Matlab results and compare with the above results\n", "rxWaveformMatlab = scipy.io.loadmat(matlabFilesPath+'/rxWaveform.mat')['rxWaveform']\n", "assert rxWaveformMatlab.shape==(numInputSamples, nr)\n", "print(\"NMSE:\", getNmse(rxWaveformMatlab.T,rxWaveform.waveform)) # NMSE between NeoRadium and Matlab results" ] }, { "cell_type": "code", "execution_count": null, "id": "b9cd7b1d-861b-4d16-91fd-062b40db8ad7", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.6" } }, "nbformat": 4, "nbformat_minor": 5 }