Sionna Block and Object
All of Sionna PHY’s components inherit from the SionnaObjectclass.
A SionnaObject is instantiated with an optionalprecision argument from which itderives complex- and real-valued data types which can be accessed via thepropertiescdtype andrdtype, respectively:
fromsionna.phyimportObjectobj=Object(precision="single")print(obj.cdtype)print(obj.rdtype)
<dtype:'complex64'><dtype:'float32'>
If theprecision argument is not provided,Objects use theglobalconfig.precision parameter, as shown next:
fromsionna.phyimportconfigfromsionna.phyimportObjectconfig.precision="double"# Set global precisionobj=Object()print(obj.cdtype)print(obj.rdtype)
<dtype:'complex128'><dtype:'float64'>
Understanding Sionna Blocks
SionnaBlocks inherit fromObjects and are used to implement most of Sionna’s components.To get an understanding of their features, let us implement a simple customBlock. EveryBlock must implement the methodcall which can take arbitrayarguments and keyword arguments. It is important to understand that all tensor argumentsare cast to theBlock’s internalprecision. Thefollowing code snippet demonstrates this behavior:
importtensorflowastffromsionna.phyimportconfigfromsionna.phyimportBlockconfig.precision="double"classMyBlock(Block):defcall(self,x,y=None):print(x.dtype)ifyisnotNone:print(y.dtype)my_block=MyBlock()x=tf.constant([3],dtype=tf.float32)y=tf.complex(2.,3.)my_block(x,y)
<dtype: 'float64'><dtype: 'complex128'>
As the internal precision of allBlocks was set via the globalprecisionflag to double preceision,the inputsx andy were cast to the corresponding dtypes prior to executingthe Block’scall method. Note that only floating data types are cast, as can beseen from the following example:
classMyBlock(Block):defcall(self,x):print(type(x))my_block=MyBlock()my_block(3)
<class 'int'>The reason for this behavior is that we sometimes need to pass non-tensorarguments to a function so that algorithms can be unrolled during the creationof the computation graph.
In many cases, aBlock require some initialization that requires the shapes ofits inputs. The first time aBlock is called, it executes thebuild methodwhich provides the shapes of all arguments and keyword arguments. The nextexample demonstrates this feature:
importnumpyasnpimporttensorflowastffromsionna.phyimportBlockclassMyBlock(Block):defbuild(self,*args,**kwargs):self.x_shape=args[0]self.y_shape=kwargs["y"]defcall(self,x,y=None):print(self.x_shape)print(x.dtype)print(self.y_shape)my_block=MyBlock()my_block(np.array([3,3]),y=tf.zeros([10,12]))
(2,)<dtype: 'float64'>(10, 12)
Note that the argumentx was provided as NumPy array which isconverted to a TensorFlow tensor within theBlock. This is in contrast to theexample above, where this did not happen for an integer input. For a detailedunderstanding of type conversions withinBlocks, we refer to the source code ofthe class methodBlock._convert_to_tensor.