Skip to content

Ray Tracing Channel Delay Spread in v1 is different from v0.19 #970

@hafezmg48

Description

@hafezmg48

The channel delay spread in the new version v1 does not seem consistent with the pervious version v0.19. In my special example below it seems that the channel spread in newer version seems to have a much larger number of shorter paths and generally very different from the delay spread seen in previous version.

A somewhat similar question was asked previously here:
#934
but the question there was only concerning the power intensity of each path being much lower. However, aside from the intensity being different, the actual delay spread is totally different which is why I asked separate question. And furthermore, even turning off the scattering with max_depth=10 the unscattered delay spread is still different from the previous version. That is why I created a new issue for this.

The following code is provided as an example in the simple street canyon with cars. A single transmitter and single reciever with the given positions and look ats. You can change the positions and still get different delay spread for v1.1 vs v0.19. You can also turn off the scattering and set max_depth to high value and see that even without scattering they are different.

from sionna.rt.scene import simple_street_canyon_with_cars

#################################################
#### CHANGE YOUR CONFIGURATIONS IN HERE ONLY ####
#################################################
max_depth = 1  # Defines max number of ray interactions

# System parameters
CarrierFreq = 10e9  
isSyntheticArray = True 

tx_center=np.array([1., -7.5, 30.])
tx_look_at = np.array([0., 0., 1.])

rx_center = np.array([-1., -7.5, 30.])
rx_look_at = np.array([0., 0., 1.])
# ray tracing sample params
num_rays =  1.e7
num_paths_keep = 20000.

scene=simple_street_canyon_with_cars

################################################


# initialize the simulation
sim = ChannelDelaySpreadSimulation(
    CarrierFreq = CarrierFreq ,
    tx_center = tx_center, 
    tx_look_at = tx_look_at ,
    rx_center = rx_center,
    rx_look_at = rx_look_at,
    num_rays = num_rays ,
    num_paths_keep = num_paths_keep,
    max_depth = max_depth,
    isSyntheticArray = isSyntheticArray,
    scene=scene
)

# compute the channel response
a_total, tau_total = sim.RT_sim_and_time_channel_estimation()


 # plot the delay spread
with tf.device('/CPU:0'): 
    a_test = np.abs(np.squeeze(a_total))
    tau_test = np.squeeze(tau_total.numpy())
plt.figure(figsize=(15,5))
plt.stem(tau_test, a_test)
plt.ylim(top=2e-5, bottom=0)
plt.grid(True)
plt.ylabel("Intensity")
plt.xlabel("Delay")
plt.title("Delay spread")
plt.savefig("delayspread.png")
plt.close()

Then
For version 0.19 use this class:

# sionna v0.19
import matplotlib.pyplot as plt
import numpy as np
import os
gpu_num = 0  # Use "" to use the CPU
os.environ["CUDA_VISIBLE_DEVICES"] = f"{gpu_num}"
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import tensorflow as tf
from sionna.rt import load_scene, Transmitter, Receiver, PlanarArray, Camera

# Configure the notebook to use only a single GPU and allocate only as much memory as needed
# For more details, see https://www.tensorflow.org/guide/gpu
gpus = tf.config.list_physical_devices('GPU')
if gpus:
    try:
        tf.config.experimental.set_memory_growth(gpus[0], True)
    except RuntimeError as e:
        print(e)

class ChannelDelaySpreadSimulation():
    def __init__(self, scene, 
                CarrierFreq,
                tx_center, tx_look_at,
                rx_center, rx_look_at,
                max_depth, num_rays, num_paths_keep,
                isSyntheticArray) -> None:

        self.CarrierFreq = CarrierFreq 
        self.tx_center = tx_center
        self.tx_look_at = tx_look_at 
        self.rx_center = rx_center
        self.rx_look_at = rx_look_at 
        self.num_rays = num_rays 
        self.num_paths_keep = num_paths_keep
        self.max_depth = max_depth
        self.isSyntheticArray = isSyntheticArray


        self.scat_keep_prob = (num_paths_keep / num_rays)

        print("Loading the Scene...")
        self.scene = load_scene(scene)
        # Configure radio materials for scattering
        # By default the scattering coefficient is set to zero
        for rm in self.scene.radio_materials.values():
            rm.scattering_coefficient = 0.5

        self.scene.frequency = CarrierFreq 

        '''channel simulation part'''
        # Configure antenna array for the transmitter
        self.scene.tx_array = PlanarArray(num_rows=1,
                                    num_cols=1,
                                    vertical_spacing=0.5,
                                    horizontal_spacing=0.5,
                                    pattern="tr38901",
                                    polarization="V")

        # Create transmitter
        tx_1 = Transmitter(name="tx_1", position=tx_center, look_at=tx_look_at) 

        # Selecting UEs based on the location and parameters of the base station
        self.scene.add(tx_1)

        # Configure antenna array for all receivers
        self.scene.rx_array = PlanarArray(num_rows=1,
                                    num_cols=1,
                                    vertical_spacing=0.5,
                                    horizontal_spacing=0.5, 
                                    pattern="tr38901",
                                    polarization="V")
        # Create receivers
        rx = Receiver(name=f"rx_1", position=rx_center, look_at=rx_look_at)
        self.scene.add(rx)

        # And visualize the scene
        tx_pos = self.scene.transmitters["tx_1"].position.numpy()
        bird_pos = tx_pos.copy()
        bird_pos[-1] = 200  # Set height of coverage map above tx
        self.bird_cam = Camera(name='bird_cam', position=bird_pos, look_at=tx_pos)


    def RT_sim_and_time_channel_estimation(self, plot=False):

        # Simulate begins
        print("Ray-Tracing Simulation...")
        tf.random.set_seed(42)
        traced_paths = self.scene.trace_paths(max_depth=self.max_depth,
                                        los=True,
                                        reflection=True,
                                        diffraction=False,
                                        scattering=True, 
                                        scat_keep_prob=self.scat_keep_prob, 
                                        num_samples=self.num_rays,
                                        check_scene=True)
        paths = self.scene.compute_fields(*traced_paths, check_scene=False)

        paths.normalize_delays = True
        a_standstill_temp, tau_standstill_temp = paths.cir()

        with tf.device('/CPU:0'):
            a_total = tf.identity(a_standstill_temp)
            tau_total = tf.identity(tau_standstill_temp)

        return a_total,  tau_total

For version 1.1 use this class:

# sionna v1.1

import matplotlib.pyplot as plt
import numpy as np
import os
gpu_num = 0  # Use "" to use the CPU
os.environ["CUDA_VISIBLE_DEVICES"] = f"{gpu_num}"
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import tensorflow as tf
from sionna.rt import load_scene, Transmitter, Receiver, PlanarArray, Camera, PathSolver

# Configure the notebook to use only a single GPU and allocate only as much memory as needed
# For more details, see https://www.tensorflow.org/guide/gpu
gpus = tf.config.list_physical_devices('GPU')
if gpus:
    try:
        tf.config.experimental.set_memory_growth(gpus[0], True)
    except RuntimeError as e:
        print(e)
tf.random.set_seed(1)  # Set global random seed for reproducibility


class ChannelDelaySpreadSimulation():
    def __init__(self, scene, 
                CarrierFreq,
                tx_center, tx_look_at,
                rx_center, rx_look_at,
                max_depth, num_rays, num_paths_keep,
                isSyntheticArray) -> None:

        self.CarrierFreq = CarrierFreq 
        self.tx_center = tx_center
        self.tx_look_at = tx_look_at 
        self.rx_center = rx_center
        self.rx_look_at = rx_look_at 
        self.num_rays = num_rays 
        self.num_paths_keep = num_paths_keep
        self.max_depth = max_depth
        self.isSyntheticArray = isSyntheticArray

        print("Loading the Scene...")
        self.scene = load_scene(scene, merge_shapes=False)
        # Configure radio materials for scattering
        # By default the scattering coefficient is set to zero
        for rm in self.scene.radio_materials.values():
            rm.scattering_coefficient = 0.5
            rm.thickness = 1.e6

        self.scene.frequency = CarrierFreq 

        '''channel simulation part'''
        # Configure antenna array for the transmitter
        self.scene.tx_array = PlanarArray(num_rows=1,
                                    num_cols=1,  
                                    pattern="tr38901",
                                    polarization="V")

        # Create transmitter
        tx_1 = Transmitter(name="tx_1", position=tx_center, look_at=tx_look_at) 

        # Selecting UEs based on the location and parameters of the base station
        self.scene.add(tx_1)

        # Configure antenna array for all receivers
        self.scene.rx_array = PlanarArray(num_rows=1,
                                    num_cols=1,
                                    pattern="tr38901",
                                    polarization="V")
        # Create receivers
        rx = Receiver(name=f"rx_1", position=rx_center, look_at=rx_look_at)
        self.scene.add(rx)

        # And visualize the scene
        tx_pos = self.scene.transmitters["tx_1"].position.numpy()
        bird_pos = tx_pos.copy()
        bird_pos[-1] = 200  # Set height of coverage map above tx
        self.bird_cam = Camera(position=bird_pos, look_at=tx_pos)


    def RT_sim_and_time_channel_estimation(self, plot=False):

        # Simulate begins
        print("Ray-Tracing Simulation...")

        solver = PathSolver()
        paths = solver( self.scene, 
                        max_depth=self.max_depth,
                        synthetic_array=self.isSyntheticArray,
                        los=True, 
                        specular_reflection=True, 
                        diffuse_reflection=True, 
                        refraction=False,
                        samples_per_src= int(self.num_paths_keep),
                        max_num_paths_per_src = int(self.num_rays) ,
                        seed = 42
                        )

        (a_real, a_img), tau = paths.cir()

        with tf.device('/CPU:0'):
            a_total = tf.complex(tf.identity(a_real), tf.identity(a_img))
            tau_total = tf.identity(tau)

        return a_total, tau_total

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions