| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- """
- Custom Keras Layers for general use
- """
- import itertools
- from tensorflow.keras import layers
- import tensorflow as tf
- import numpy as np
- class AwgnChannel(layers.Layer):
- def __init__(self, rx_stddev=0.1, noise_dB=None, **kwargs):
- """
- :param rx_stddev: Standard deviation of receiver noise (due to e.g. TIA circuit)
- """
- super(AwgnChannel, self).__init__(**kwargs)
- if noise_dB is not None:
- # rx_stddev = np.sqrt(1 / (20 ** (noise_dB / 10.0)))
- rx_stddev = 10 ** (noise_dB / 10.0)
- self.noise_layer = layers.GaussianNoise(rx_stddev)
- def call(self, inputs, **kwargs):
- return self.noise_layer.call(inputs, training=True)
- class ScaleAndOffset(layers.Layer):
- """
- Scales and offsets a tensor
- """
- def __init__(self, scale=1, offset=0, **kwargs):
- super(ScaleAndOffset, self).__init__(**kwargs)
- self.offset = offset
- self.scale = scale
- def call(self, inputs, **kwargs):
- return inputs * self.scale + self.offset
- class BitsToSymbol(layers.Layer):
- def __init__(self, cardinality, **kwargs):
- super().__init__(**kwargs)
- self.cardinality = cardinality
- n = int(np.log(self.cardinality, 2))
- self.powers = tf.convert_to_tensor(
- np.power(2, np.linspace(n - 1, 0, n)).reshape(-1, 1),
- dtype=tf.float32
- )
- def call(self, inputs, **kwargs):
- idx = tf.cast(tf.tensordot(inputs, self.powers, axes=1), dtype=tf.int32)
- return tf.one_hot(idx, self.cardinality)
- class SymbolToBits(layers.Layer):
- def __init__(self, cardinality, **kwargs):
- super().__init__(**kwargs)
- n = int(np.log(cardinality, 2))
- l = [list(i) for i in itertools.product([0, 1], repeat=n)]
- self.all_syms = tf.transpose(tf.convert_to_tensor(np.asarray(l), dtype=tf.float32))
- def call(self, inputs, **kwargs):
- return tf.matmul(self.all_syms, inputs)
|