Open
Description
I got what I think are exceptionally high SNRs with the SIONNA UMa channel model when simulating OFDM channels.
I am expecting 20 to -3 dB of SNRs across 1000 meters.
Is it because the TOTAL transmission power was allocated to 76 OFDM subcarriers?
Or is it normal (i.e., as expected for a 3GPP UMa)? I've been searching for references for SNR vs Distance curvatures under 3GPP UMa/UMi/RMa models but haven't found any.
import sionna as sn
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from matplotlib import cm
# Define the number of UT and BS antennas
NUM_UT = 1
NUM_BS = 1
NUM_UT_ANT = 1
NUM_BS_ANT = 1
# The number of transmitted streams is equal to the number of UT antennas
# in both uplink and downlink
NUM_STREAMS_PER_TX = NUM_UT_ANT
# In this notebook, as we have only a single transmitter and receiver,
# the RX-TX association matrix is simply:
RX_TX_ASSOCIATION = np.array([[1]])
# Instantiate a StreamManagement object
# This determines which data streams are determined for which receiver.
# In this simple setup, this is fairly easy. However, it can get more involved
# for simulations with many transmitters and receivers.
STREAM_MANAGEMENT = sn.mimo.StreamManagement(RX_TX_ASSOCIATION, NUM_STREAMS_PER_TX)
# Setup resource grid and channel model
sm = sn.mimo.StreamManagement(np.array([[1]]), 1)
RESOURCE_GRID = sn.ofdm.ResourceGrid(num_ofdm_symbols=14,
fft_size=76,
subcarrier_spacing=30e3,
num_tx=NUM_UT,
num_streams_per_tx=NUM_STREAMS_PER_TX,
cyclic_prefix_length=6,
pilot_pattern="kronecker",
pilot_ofdm_symbol_indices=[2, 11])
# RESOURCE_GRID.show()
CARRIER_FREQUENCY = 2.6e9 # Carrier frequency in Hz.
# This is needed here to define the antenna element spacing.
UT_ARRAY = sn.channel.tr38901.Antenna(polarization="single",
polarization_type="V",
antenna_pattern="38.901",
carrier_frequency=CARRIER_FREQUENCY)
UT_ARRAY.show()
BS_ARRAY = sn.channel.tr38901.AntennaArray(num_rows=1,
num_cols=NUM_BS_ANT,
polarization="single",
polarization_type="V",
antenna_pattern="38.901", # Try 'omni'
carrier_frequency=CARRIER_FREQUENCY)
BS_ARRAY.show()
BATCH_SIZE = 200
distance = np.linspace(1, 1000, 250)
bs_loc = tf.zeros(shape=(BATCH_SIZE, NUM_BS, 3), dtype=tf.float32)
ut_locs = np.zeros(shape=(BATCH_SIZE, len(distance), 3))
for b in range(BATCH_SIZE):
ut_locs[b, :, 1] = distance
ut_locs = tf.convert_to_tensor(ut_locs, dtype=tf.float32)
bs_ori = tf.zeros(shape=(BATCH_SIZE, NUM_BS, 3), dtype=tf.float32)
ut_ori = np.zeros(shape=(BATCH_SIZE, NUM_UT, 3))
ut_ori[:, :, 0] = np.pi
ut_ori = tf.convert_to_tensor(ut_ori, dtype=tf.float32)
ut_vol = tf.zeros(shape=(BATCH_SIZE, NUM_UT, 3), dtype=tf.float32)
in_state = tf.zeros(shape=(BATCH_SIZE, NUM_UT), dtype=tf.bool)
# power_tx_dbm = -20 # Downlink Power Spectrum Density (PSD)
# power_tx = 10**(power_tx_dbm/10) # Tx power
# power_tx_sub = power_tx/RESOURCE_GRID.fft_size # Tx power per subcarrier
# power_tx = (10 ** (power_tx_dbm / 10))*RESOURCE_GRID.subcarrier_spacing # Tx power per symbol
power_tx = 1
k = 1.38*10**(-23) # Boltzmann's constant
T = 293 # Absolute temperature in Kelvin
n0_sub = k*T*RESOURCE_GRID.subcarrier_spacing # Noise power per subcarrier
SNRs = np.zeros(shape=(len(distance), RESOURCE_GRID.fft_size))
UMa = sn.channel.tr38901.UMa(carrier_frequency=3.5e9,
o2i_model='low',
ut_array=UT_ARRAY,
bs_array=BS_ARRAY,
direction='downlink',
enable_pathloss=True)
# Configure topology for channel model
UMa.set_topology(ut_locs, bs_loc, ut_ori, bs_ori, ut_vol, in_state=in_state, los=True)
# Generating OFDM channel
generate_channel = sn.channel.GenerateOFDMChannel(channel_model=UMa, resource_grid=RESOURCE_GRID)
# Generate a batch of channel responses
h_list = generate_channel()
check = tf.reduce_mean(tf.square(tf.abs(h_list)), axis=[0, 5])
# Apply OFDM channels
apply_channel = sn.channel.ApplyOFDMChannel(add_awgn=False)
for d in range(len(distance)):
# Select a batch of channel responses
h = h_list[:, d:d+1, :, :, :, :, :]
# Generate channel inputs
shape_in = (BATCH_SIZE, NUM_BS, NUM_BS_ANT, RESOURCE_GRID.num_ofdm_symbols, RESOURCE_GRID.fft_size)
x_real = tf.random.uniform(shape_in, minval=0, maxval=2, dtype=tf.int32) # Random real part
x_real = tf.where(x_real == 0, -1, 1)
x_real = np.sqrt(power_tx/2)*tf.cast(x_real, dtype=tf.float32)
x_imag = tf.random.uniform(shape_in, minval=0, maxval=2, dtype=tf.int32) # Random imaginary part
x_imag = tf.where(x_imag == 0, -1, 1)
x_imag = np.sqrt(power_tx/2)*tf.cast(x_imag, dtype=tf.float32)
x = tf.complex(x_real, x_imag)
# Generate noise variances
shape_out = (BATCH_SIZE, NUM_UT, NUM_UT_ANT, RESOURCE_GRID.num_ofdm_symbols, RESOURCE_GRID.fft_size)
no = n0_sub*np.ones(shape=shape_out, dtype=np.float32)
y = apply_channel([x, h])
no, y = np.squeeze(no), tf.squeeze(y).numpy()
y_p = np.square(np.abs(y))
snr_ins = 10*np.log10(np.divide(y_p, no))
snr_ero = np.mean(snr_ins, axis=0)
snr_ero = np.mean(snr_ero, axis=0)
SNRs[d, :] = snr_ero
# Visualize results
X, Y = np.meshgrid(range(RESOURCE_GRID.fft_size), distance)
# Plot the surface
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
surf = ax.plot_surface(X, Y, SNRs, vmin=SNRs.min(), cmap=cm.viridis)
fig.colorbar(surf, shrink=0.5, aspect=5)
ax.set_xlabel('frequency')
ax.set_ylabel('distance')
ax.set_zlabel('SNR (dB)')
# plt.show()
plt.figure()
plt.title("SNRs vs Distance")
for cid in range(RESOURCE_GRID.fft_size):
plt.plot(distance, SNRs[:, cid])
plt.xlabel(r"distance (m)")
plt.ylabel(r"SNR (dB)")
plt.grid()
plt.show()
Could you please tell me where I did wrong in this code?
Thank you very much!
Metadata
Metadata
Assignees
Labels
No labels