├── LICENSE ├── README.md ├── autoencoder_for_MIMO_with_gaussian.ipynb ├── autoencoder_with_gaussian.ipynb ├── autoencoder_with_reiligh_1_2.ipynb ├── autoencoder_with_reiligh_1_2_and_RTN_reciever.ipynb └── siso_info_and_power_transfer_with_white_noise.ipynb /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jayden Booth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | This is my attempt to reproduce and extend the results in the paper "An Introduction to Deep Learning for the Physical Layer" by Tim O'Shea and Jakob Hoydis. Available at https://doi.org/10.1109/TCCN.2017.2758370 3 | 4 | There is also and attempt to use the autoencoder for simultaneous information and power transfer, based on the paper "A Learning Approach to Wireless Information and Power Transfer Signal And System Design" by Morteza Varasteh, Enrico Piovano, and Bruno Clerckx. Available at https://doi.org/10.1109/ICASSP.2019.8682485 5 | 6 | Another very useful paper on this topic is "Deep Learning-Based Communication Over the Air" By Sebastian Dorner, Sebastian Cammerer, Jakob Hoydis, and Stephan ten Brink. It covers more complicated implementations for more realistic channels. 7 | 8 | The implementation uses Keras with a Tensorflow backend on Jupyter Notebook. The paper from O'Shea and Hoydis covers multiple applications for using an autoencoder to replace the physical layer in a wireless communication system. I have searched and only found code for the most basic example, which implements a Gaussian Channel, but for the three more complex applications there is nothing. Therefore I am reproducing the results myself. Currently I have only reproduced the results for the Gaussian Channel. The end goal for this is to implement the trained encoder and decoder in real-time using GNU Radio and the gr-tflite module (which I am planning on writing). 9 | 10 | # Autoencoder for Gaussian Channel 11 | This creates an autoencoder which finds the optimal modulating technique for robust communication over a white gaussian noise channel (the simplest of channels). The Block Error Rate of the communication through varying Signal to Noise Ratios is analyzed by varying the magnitude of added noise. The trained autoencoder successfully transmits the signal with performance comparable to other 12 | 13 | # Autoencoder for Reyleigh Channel 14 | This Attempts to implement an autencoder with similar structure the the previous Gaussian Channel to a Reyleigh Channel. Currently, only a single tap Reyleigh Channel has been implemented, and is currently not effective. 15 | 16 | # Autoencoder for Reyleigh Channel with RTN 17 | This is an improvement to the decoder portion of the autoencoder by including a RTN which predicts the channel taps and then performs a convolution using the recieved signal and predicted channel taps. In the paper "An Introduction to Deep Learning for the Physical Layer" this technique significantly improved the Block Error Rate of the system, but I have been unable to reproduce these results. 18 | 19 | # Autoencoder for MIMO Communication with a Gaussian Channel 20 | This attempts to create two autoencoders that reject the other, allowing a communication between two systems. Here the output of one encoder is added to the output of the other encoder with white gaussian noise and is then recieved by the corresponding decoder, and vice versa. Interestingly enough, without a special adaptive loss function the combined system tends to highly optimize one of the channels at the cost of the other channel, where one channel will recive small BER and the other will have large BER. To overcome this I have implemented a custom loss function that weights the loss of each seperate autoencoder according to the accuracy of the previous batch. Currently this is not yet effective, and requires more work. 21 | 22 | # SISO for Simultaneous Info and Power Transfer 23 | This is another interesting application of autoencoders to the physical layer. This attempt only uses a Gaussian Channel, and I have run into problems because the loss function used in the paper incorporates a modified bessel function of the first kind and zero order. Incorporating only the bessel function causes the loss to return as NaN because the bessel function returns extremely large numbers. Currently the code implements the natural log of the bessel function to avoid this, but I must do more reading to understand the purpose of this bessel function, because currently my calculations of recieved power do not match the recieved power presented in the paper. 24 | 25 | # License 26 | This code is licensed under the MIT Open Source License. 27 | -------------------------------------------------------------------------------- /autoencoder_with_gaussian.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "Using TensorFlow backend.\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "# MIT License\n", 18 | "\n", 19 | "# Copyright (c) [2019] [Jayden Booth]\n", 20 | "\n", 21 | "# Permission is hereby granted, free of charge, to any person obtaining a copy\n", 22 | "# of this software and associated documentation files (the \"Software\"), to deal\n", 23 | "# in the Software without restriction, including without limitation the rights\n", 24 | "# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n", 25 | "# copies of the Software, and to permit persons to whom the Software is\n", 26 | "# furnished to do so, subject to the following conditions:\n", 27 | "\n", 28 | "# The above copyright notice and this permission notice shall be included in all\n", 29 | "# copies or substantial portions of the Software.\n", 30 | "\n", 31 | "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n", 32 | "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n", 33 | "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n", 34 | "# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n", 35 | "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n", 36 | "# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n", 37 | "# SOFTWARE.\n", 38 | "\n", 39 | "# Import Libraries\n", 40 | "import numpy as np\n", 41 | "import tensorflow as tf\n", 42 | "import keras\n", 43 | "from keras.layers import Input, Dense, GaussianNoise,Lambda,Dropout, Concatenate\n", 44 | "from keras.models import Model\n", 45 | "from keras import regularizers\n", 46 | "from keras.layers.normalization import BatchNormalization\n", 47 | "from keras.optimizers import Adam,SGD\n", 48 | "from keras import backend as K\n", 49 | "%matplotlib inline" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 2, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# Set random seeds\n", 59 | "from numpy.random import seed\n", 60 | "seed(1)\n", 61 | "from tensorflow import set_random_seed\n", 62 | "set_random_seed(3)" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 3, 68 | "metadata": {}, 69 | "outputs": [ 70 | { 71 | "name": "stdout", 72 | "output_type": "stream", 73 | "text": [ 74 | "M: 16 \t n: 1\n" 75 | ] 76 | } 77 | ], 78 | "source": [ 79 | "# Set the defining parameters\n", 80 | "# n = n_channel complex numbers (so 2n real numbers)\n", 81 | "# k = log2(M), where M is the number of messages to encode\n", 82 | "# EbNo is the energy per bit to noise power density\n", 83 | "\n", 84 | "# Encoder Parameters\n", 85 | "M = 16\n", 86 | "k = np.log2(M)\n", 87 | "n_channel = 1\n", 88 | "R = k/n_channel\n", 89 | "tx_power = 2\n", 90 | "print('M:',M,'\\t','n:',n_channel)\n", 91 | "\n", 92 | "# Channel Parameters\n", 93 | "EbNo=10.0**(7/10.0)\n", 94 | "noise_std = np.sqrt(1/(2*R*EbNo))\n", 95 | "num_taps = 1\n", 96 | "reyleigh_std = num_taps/np.sqrt(2)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "#generating data of size N\n", 106 | "N = 16000\n", 107 | "label = np.random.randint(M,size=N)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 5, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "# creating one hot encoded vectors\n", 117 | "data = []\n", 118 | "for i in label:\n", 119 | " temp = np.zeros(M)\n", 120 | " temp[i] = 1\n", 121 | " data.append(temp)" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 6, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "name": "stdout", 131 | "output_type": "stream", 132 | "text": [ 133 | "(16000, 16)\n" 134 | ] 135 | } 136 | ], 137 | "source": [ 138 | "# checking data shape\n", 139 | "data = np.array(data)\n", 140 | "print (data.shape)" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 7, 146 | "metadata": {}, 147 | "outputs": [ 148 | { 149 | "name": "stdout", 150 | "output_type": "stream", 151 | "text": [ 152 | "9 [0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]\n", 153 | "4 [0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 154 | "13 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]\n", 155 | "3 [0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 156 | "9 [0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]\n", 157 | "7 [0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 158 | "12 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]\n", 159 | "15 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]\n", 160 | "12 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]\n" 161 | ] 162 | } 163 | ], 164 | "source": [ 165 | "# checking generated data with it's label\n", 166 | "temp_check = [17,23,45,67,89,96,72,250,350]\n", 167 | "for i in temp_check:\n", 168 | " print(label[i],data[i])" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 8, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [ 177 | "# Average Power Normalization\n", 178 | "def fixed_power_norm(x):\n", 179 | " P_avg = 0.04\n", 180 | " beta = K.sqrt(K.sum(K.square(x)))\n", 181 | " return x / beta" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 9, 187 | "metadata": {}, 188 | "outputs": [ 189 | { 190 | "name": "stderr", 191 | "output_type": "stream", 192 | "text": [ 193 | "WARNING: Logging before flag parsing goes to stderr.\n", 194 | "W0718 12:59:58.382695 140555158988608 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", 195 | "\n", 196 | "W0718 12:59:58.383541 140555158988608 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", 197 | "\n", 198 | "W0718 12:59:58.386196 140555158988608 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", 199 | "\n", 200 | "W0718 12:59:58.464284 140555158988608 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:133: The name tf.placeholder_with_default is deprecated. Please use tf.compat.v1.placeholder_with_default instead.\n", 201 | "\n", 202 | "W0718 12:59:58.490715 140555158988608 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:4115: The name tf.random_normal is deprecated. Please use tf.random.normal instead.\n", 203 | "\n", 204 | "W0718 12:59:58.536745 140555158988608 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", 205 | "\n" 206 | ] 207 | } 208 | ], 209 | "source": [ 210 | "# Defined Autoencoder\n", 211 | "\n", 212 | "# Transmitter Layers\n", 213 | "input_signal = Input(shape=(M,))\n", 214 | "encoded = Dense(M, activation='relu')(input_signal)\n", 215 | "encoded1 = Dense(2*n_channel, activation='linear')(encoded)\n", 216 | "encoded2 = BatchNormalization()(encoded1)\n", 217 | "encoded3 = Lambda(lambda x: tx_power/np.sqrt(2)*K.l2_normalize(x,axis=-1))(encoded2)\n", 218 | "\n", 219 | "# Gaussian Channel Layer\n", 220 | "EbNo_train = 5.01187 # coverted 7 db of EbNo\n", 221 | "channel1 = GaussianNoise(np.sqrt(1/(2*R*EbNo_train)))(encoded3)\n", 222 | "\n", 223 | "# Reciever Layer\n", 224 | "decoded = Dense(M, activation='relu')(channel1)\n", 225 | "decoded1 = Dense(M, activation='softmax')(decoded)\n", 226 | "autoencoder = Model(input_signal, decoded1)\n", 227 | "adam = Adam(lr=0.01)\n", 228 | "sgd = SGD(lr=0.02)\n", 229 | "autoencoder.compile(optimizer=adam, loss='categorical_crossentropy')" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 10, 235 | "metadata": {}, 236 | "outputs": [ 237 | { 238 | "name": "stdout", 239 | "output_type": "stream", 240 | "text": [ 241 | "_________________________________________________________________\n", 242 | "Layer (type) Output Shape Param # \n", 243 | "=================================================================\n", 244 | "input_1 (InputLayer) (None, 16) 0 \n", 245 | "_________________________________________________________________\n", 246 | "dense_1 (Dense) (None, 16) 272 \n", 247 | "_________________________________________________________________\n", 248 | "dense_2 (Dense) (None, 2) 34 \n", 249 | "_________________________________________________________________\n", 250 | "batch_normalization_1 (Batch (None, 2) 8 \n", 251 | "_________________________________________________________________\n", 252 | "lambda_1 (Lambda) (None, 2) 0 \n", 253 | "_________________________________________________________________\n", 254 | "gaussian_noise_1 (GaussianNo (None, 2) 0 \n", 255 | "_________________________________________________________________\n", 256 | "dense_3 (Dense) (None, 16) 48 \n", 257 | "_________________________________________________________________\n", 258 | "dense_4 (Dense) (None, 16) 272 \n", 259 | "=================================================================\n", 260 | "Total params: 634\n", 261 | "Trainable params: 630\n", 262 | "Non-trainable params: 4\n", 263 | "_________________________________________________________________\n", 264 | "None\n" 265 | ] 266 | } 267 | ], 268 | "source": [ 269 | "# printing summary of layers and it's trainable parameters \n", 270 | "print (autoencoder.summary())" 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "execution_count": 11, 276 | "metadata": {}, 277 | "outputs": [ 278 | { 279 | "name": "stderr", 280 | "output_type": "stream", 281 | "text": [ 282 | "W0718 12:59:58.631593 140555158988608 deprecation.py:323] From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", 283 | "Instructions for updating:\n", 284 | "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" 285 | ] 286 | }, 287 | { 288 | "name": "stdout", 289 | "output_type": "stream", 290 | "text": [ 291 | "Epoch 1/50\n", 292 | "16000/16000 [==============================] - 1s 78us/step - loss: 2.4376\n", 293 | "Epoch 2/50\n", 294 | "16000/16000 [==============================] - 0s 4us/step - loss: 1.8235\n", 295 | "Epoch 3/50\n", 296 | "16000/16000 [==============================] - 0s 4us/step - loss: 1.4144\n", 297 | "Epoch 4/50\n", 298 | "16000/16000 [==============================] - 0s 4us/step - loss: 1.1208\n", 299 | "Epoch 5/50\n", 300 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.9124\n", 301 | "Epoch 6/50\n", 302 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.7711\n", 303 | "Epoch 7/50\n", 304 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.6736\n", 305 | "Epoch 8/50\n", 306 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.5989\n", 307 | "Epoch 9/50\n", 308 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.5381\n", 309 | "Epoch 10/50\n", 310 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.4965\n", 311 | "Epoch 11/50\n", 312 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.4600\n", 313 | "Epoch 12/50\n", 314 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.4270\n", 315 | "Epoch 13/50\n", 316 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.4085\n", 317 | "Epoch 14/50\n", 318 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.3865\n", 319 | "Epoch 15/50\n", 320 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.3542\n", 321 | "Epoch 16/50\n", 322 | "16000/16000 [==============================] - 0s 5us/step - loss: 0.3391\n", 323 | "Epoch 17/50\n", 324 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.3400\n", 325 | "Epoch 18/50\n", 326 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.3249\n", 327 | "Epoch 19/50\n", 328 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.3038\n", 329 | "Epoch 20/50\n", 330 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.3038\n", 331 | "Epoch 21/50\n", 332 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2921\n", 333 | "Epoch 22/50\n", 334 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2994\n", 335 | "Epoch 23/50\n", 336 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2768\n", 337 | "Epoch 24/50\n", 338 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2755\n", 339 | "Epoch 25/50\n", 340 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2740\n", 341 | "Epoch 26/50\n", 342 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2770\n", 343 | "Epoch 27/50\n", 344 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2767\n", 345 | "Epoch 28/50\n", 346 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2737\n", 347 | "Epoch 29/50\n", 348 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2680\n", 349 | "Epoch 30/50\n", 350 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2754\n", 351 | "Epoch 31/50\n", 352 | "16000/16000 [==============================] - 0s 7us/step - loss: 0.2706\n", 353 | "Epoch 32/50\n", 354 | "16000/16000 [==============================] - 0s 3us/step - loss: 0.2565\n", 355 | "Epoch 33/50\n", 356 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2585\n", 357 | "Epoch 34/50\n", 358 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2650\n", 359 | "Epoch 35/50\n", 360 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2569\n", 361 | "Epoch 36/50\n", 362 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2529\n", 363 | "Epoch 37/50\n", 364 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2639\n", 365 | "Epoch 38/50\n", 366 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2519\n", 367 | "Epoch 39/50\n", 368 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2491\n", 369 | "Epoch 40/50\n", 370 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2676\n", 371 | "Epoch 41/50\n", 372 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2749\n", 373 | "Epoch 42/50\n", 374 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2415\n", 375 | "Epoch 43/50\n", 376 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2448\n", 377 | "Epoch 44/50\n", 378 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2478\n", 379 | "Epoch 45/50\n", 380 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2456\n", 381 | "Epoch 46/50\n", 382 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2593\n", 383 | "Epoch 47/50\n", 384 | "16000/16000 [==============================] - 0s 5us/step - loss: 0.2488\n", 385 | "Epoch 48/50\n", 386 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2593\n", 387 | "Epoch 49/50\n", 388 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2470\n", 389 | "Epoch 50/50\n", 390 | "16000/16000 [==============================] - 0s 4us/step - loss: 0.2455\n" 391 | ] 392 | }, 393 | { 394 | "data": { 395 | "text/plain": [ 396 | "" 397 | ] 398 | }, 399 | "execution_count": 11, 400 | "metadata": {}, 401 | "output_type": "execute_result" 402 | } 403 | ], 404 | "source": [ 405 | "# traning auto encoder\n", 406 | "autoencoder.fit(data, data,\n", 407 | " epochs=50,\n", 408 | " batch_size=1024)" 409 | ] 410 | }, 411 | { 412 | "cell_type": "code", 413 | "execution_count": 12, 414 | "metadata": {}, 415 | "outputs": [], 416 | "source": [ 417 | "# making encoder from full autoencoder\n", 418 | "encoder = Model(input_signal, encoded3)" 419 | ] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "execution_count": 13, 424 | "metadata": {}, 425 | "outputs": [], 426 | "source": [ 427 | "# making channel from full autoencoder\n", 428 | "channel_input = Input(shape=(2*n_channel,))\n", 429 | "\n", 430 | "chan = autoencoder.layers[-3](channel_input)\n", 431 | "channel_layer = Model(channel_input,chan)" 432 | ] 433 | }, 434 | { 435 | "cell_type": "code", 436 | "execution_count": 14, 437 | "metadata": {}, 438 | "outputs": [], 439 | "source": [ 440 | "# making decoder from full autoencoder\n", 441 | "encoded_input = Input(shape=(2*n_channel,))\n", 442 | "\n", 443 | "deco = autoencoder.layers[-2](encoded_input)\n", 444 | "deco = autoencoder.layers[-1](deco)\n", 445 | "decoder = Model(encoded_input, deco)" 446 | ] 447 | }, 448 | { 449 | "cell_type": "code", 450 | "execution_count": 15, 451 | "metadata": {}, 452 | "outputs": [], 453 | "source": [ 454 | "# generating data for checking BER\n", 455 | "N = 100000\n", 456 | "test_label = np.random.randint(M,size=N)\n", 457 | "test_data = []\n", 458 | "\n", 459 | "for i in test_label:\n", 460 | " temp = np.zeros(M)\n", 461 | " temp[i] = 1\n", 462 | " test_data.append(temp)\n", 463 | " \n", 464 | "test_data = np.array(test_data)" 465 | ] 466 | }, 467 | { 468 | "cell_type": "code", 469 | "execution_count": 16, 470 | "metadata": {}, 471 | "outputs": [ 472 | { 473 | "name": "stdout", 474 | "output_type": "stream", 475 | "text": [ 476 | "(16, 1, 2)\n" 477 | ] 478 | } 479 | ], 480 | "source": [ 481 | "# for plotting learned consteallation diagram\n", 482 | "\n", 483 | "scatter_plot = []\n", 484 | "for i in range(0,M):\n", 485 | " temp = np.zeros(M)\n", 486 | " temp[i] = 1\n", 487 | " scatter_plot.append(encoder.predict(np.expand_dims(temp,axis=0)))\n", 488 | "scatter_plot = 1.5/2*np.array(scatter_plot)\n", 489 | "print (scatter_plot.shape)" 490 | ] 491 | }, 492 | { 493 | "cell_type": "code", 494 | "execution_count": 17, 495 | "metadata": {}, 496 | "outputs": [ 497 | { 498 | "data": { 499 | "image/png": "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\n", 500 | "text/plain": [ 501 | "
" 502 | ] 503 | }, 504 | "metadata": { 505 | "needs_background": "light" 506 | }, 507 | "output_type": "display_data" 508 | } 509 | ], 510 | "source": [ 511 | "# ploting constellation diagram\n", 512 | "import matplotlib.pyplot as plt\n", 513 | "scatter_plot = scatter_plot.reshape(M,2,1)\n", 514 | "plt.scatter(scatter_plot[:,0],scatter_plot[:,1])\n", 515 | "#plt.axis((-2.5,2.5,-2.5,2.5))\n", 516 | "plt.grid()\n", 517 | "plt.xlabel('I Axis')\n", 518 | "plt.ylabel('Q Axis')\n", 519 | "plt.show()" 520 | ] 521 | }, 522 | { 523 | "cell_type": "code", 524 | "execution_count": 18, 525 | "metadata": {}, 526 | "outputs": [ 527 | { 528 | "name": "stdout", 529 | "output_type": "stream", 530 | "text": [ 531 | "SNR: 0 BER: 0.45201\n", 532 | "SNR: 2 BER: 0.35282\n", 533 | "SNR: 4 BER: 0.24923\n", 534 | "SNR: 6 BER: 0.16253\n", 535 | "SNR: 8 BER: 0.09706\n", 536 | "SNR: 10 BER: 0.05061\n", 537 | "SNR: 12 BER: 0.02182\n", 538 | "SNR: 14 BER: 0.00742\n", 539 | "SNR: 16 BER: 0.00177\n", 540 | "SNR: 18 BER: 0.00023\n", 541 | "SNR: 20 BER: 0.0\n" 542 | ] 543 | } 544 | ], 545 | "source": [ 546 | "# Calculating BER from 0dB to 20dB SNR\n", 547 | "EbNodB_range = list(np.arange(0,20+1,2))\n", 548 | "ber = [None]*len(EbNodB_range)\n", 549 | "for n in range(0,len(EbNodB_range)):\n", 550 | " EbNo=10.0**(EbNodB_range[n]/10.0)\n", 551 | " noise_std = np.sqrt(1/(2*R*EbNo))\n", 552 | " noise_mean = 0\n", 553 | " no_errors = 0\n", 554 | " nn = N\n", 555 | " noise = noise_std*np.random.randn(nn,2*n_channel)\n", 556 | " encoded_signal = encoder.predict(test_data) \n", 557 | " final_signal = encoded_signal+noise\n", 558 | " pred_final_signal = decoder.predict(final_signal)\n", 559 | " pred_output = np.argmax(pred_final_signal,axis=1)\n", 560 | " no_errors = (pred_output != test_label)\n", 561 | " no_errors = no_errors.astype(int).sum()\n", 562 | " ber[n] = no_errors / nn \n", 563 | " print ('SNR:',EbNodB_range[n],'BER:',ber[n])" 564 | ] 565 | }, 566 | { 567 | "cell_type": "code", 568 | "execution_count": 19, 569 | "metadata": {}, 570 | "outputs": [ 571 | { 572 | "data": { 573 | "image/png": "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\n", 574 | "text/plain": [ 575 | "
" 576 | ] 577 | }, 578 | "metadata": { 579 | "needs_background": "light" 580 | }, 581 | "output_type": "display_data" 582 | } 583 | ], 584 | "source": [ 585 | "# ploting BER curve\n", 586 | "import matplotlib.pyplot as plt\n", 587 | "from scipy import interpolate\n", 588 | "plt.plot(EbNodB_range, ber, 'bo',label='Autoencoder(1,2)')\n", 589 | "plt.yscale('log')\n", 590 | "plt.xlabel('SNR Range')\n", 591 | "plt.ylabel('Block Error Rate')\n", 592 | "plt.grid()\n", 593 | "plt.legend(loc='upper right',ncol = 1)\n", 594 | "plt.show()" 595 | ] 596 | }, 597 | { 598 | "cell_type": "code", 599 | "execution_count": null, 600 | "metadata": {}, 601 | "outputs": [], 602 | "source": [] 603 | } 604 | ], 605 | "metadata": { 606 | "kernelspec": { 607 | "display_name": "Python 3", 608 | "language": "python", 609 | "name": "python3" 610 | }, 611 | "language_info": { 612 | "codemirror_mode": { 613 | "name": "ipython", 614 | "version": 3 615 | }, 616 | "file_extension": ".py", 617 | "mimetype": "text/x-python", 618 | "name": "python", 619 | "nbconvert_exporter": "python", 620 | "pygments_lexer": "ipython3", 621 | "version": "3.6.8" 622 | } 623 | }, 624 | "nbformat": 4, 625 | "nbformat_minor": 2 626 | } 627 | -------------------------------------------------------------------------------- /autoencoder_with_reiligh_1_2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "Using TensorFlow backend.\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "# MIT License\n", 18 | "\n", 19 | "# Copyright (c) [2019] [Jayden Booth]\n", 20 | "\n", 21 | "# Permission is hereby granted, free of charge, to any person obtaining a copy\n", 22 | "# of this software and associated documentation files (the \"Software\"), to deal\n", 23 | "# in the Software without restriction, including without limitation the rights\n", 24 | "# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n", 25 | "# copies of the Software, and to permit persons to whom the Software is\n", 26 | "# furnished to do so, subject to the following conditions:\n", 27 | "\n", 28 | "# The above copyright notice and this permission notice shall be included in all\n", 29 | "# copies or substantial portions of the Software.\n", 30 | "\n", 31 | "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n", 32 | "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n", 33 | "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n", 34 | "# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n", 35 | "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n", 36 | "# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n", 37 | "# SOFTWARE.\n", 38 | "\n", 39 | "# Import Libraries\n", 40 | "import numpy as np\n", 41 | "import tensorflow as tf\n", 42 | "import keras\n", 43 | "from keras.layers import Input, Dense, GaussianNoise,Lambda,Dropout, Concatenate\n", 44 | "from keras.models import Model\n", 45 | "from keras import regularizers\n", 46 | "from keras.layers.normalization import BatchNormalization\n", 47 | "from keras.optimizers import Adam,SGD\n", 48 | "from keras import backend as K\n", 49 | "%matplotlib inline" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 2, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# Set random seeds\n", 59 | "from numpy.random import seed\n", 60 | "seed(1)\n", 61 | "from tensorflow import set_random_seed\n", 62 | "set_random_seed(3)" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 3, 68 | "metadata": {}, 69 | "outputs": [ 70 | { 71 | "name": "stdout", 72 | "output_type": "stream", 73 | "text": [ 74 | "M: 4 \t n: 1\n" 75 | ] 76 | } 77 | ], 78 | "source": [ 79 | "# Set the defining parameters\n", 80 | "# n = n_channel complex numbers (so 2n real numbers)\n", 81 | "# k = log2(M), where M is the number of messages to encode\n", 82 | "# EbNo is the energy per bit to noise power density\n", 83 | "\n", 84 | "# Encoder Parameters\n", 85 | "M = 4\n", 86 | "k = np.log2(M)\n", 87 | "n_channel = 1\n", 88 | "R = k/n_channel\n", 89 | "power = 2\n", 90 | "print('M:',M,'\\t','n:',n_channel)\n", 91 | "\n", 92 | "# Channel Parameters\n", 93 | "EbNo=10.0**(7/10.0)\n", 94 | "noise_std = np.sqrt(1/(2*R*EbNo))\n", 95 | "num_taps = 1\n", 96 | "reyleigh_std = num_taps/np.sqrt(2)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "#generating data of size N\n", 106 | "N = 16000\n", 107 | "label = np.random.randint(M,size=N)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 5, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "# creating one hot encoded vectors\n", 117 | "data = []\n", 118 | "for i in label:\n", 119 | " temp = np.zeros(M)\n", 120 | " temp[i] = 1\n", 121 | " data.append(temp)" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 6, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "name": "stdout", 131 | "output_type": "stream", 132 | "text": [ 133 | "(16000, 4)\n" 134 | ] 135 | } 136 | ], 137 | "source": [ 138 | "# checking data shape\n", 139 | "data = np.array(data)\n", 140 | "print (data.shape)" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 7, 146 | "metadata": {}, 147 | "outputs": [ 148 | { 149 | "name": "stdout", 150 | "output_type": "stream", 151 | "text": [ 152 | "1 [0. 1. 0. 0.]\n", 153 | "0 [1. 0. 0. 0.]\n", 154 | "1 [0. 1. 0. 0.]\n", 155 | "3 [0. 0. 0. 1.]\n", 156 | "1 [0. 1. 0. 0.]\n", 157 | "3 [0. 0. 0. 1.]\n", 158 | "0 [1. 0. 0. 0.]\n", 159 | "3 [0. 0. 0. 1.]\n", 160 | "0 [1. 0. 0. 0.]\n" 161 | ] 162 | } 163 | ], 164 | "source": [ 165 | "# checking generated data with it's label\n", 166 | "temp_check = [17,23,45,67,89,96,72,250,350]\n", 167 | "for i in temp_check:\n", 168 | " print(label[i],data[i])" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 8, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [ 177 | "# Functions that define the Channel. \n", 178 | "\n", 179 | "# First the encoder output must be converted to complex samples \n", 180 | "# Right now I am assuming n = 1 for simplicity\n", 181 | "\n", 182 | "def real_to_complex(x):\n", 183 | " real = x[:,0]\n", 184 | " imag = x[:,1]\n", 185 | " return tf.reshape(tf.dtypes.complex(real,imag),shape=[-1,1])\n", 186 | "\n", 187 | "def complex_to_real(x):\n", 188 | " real = tf.math.real(x)\n", 189 | " imag = tf.math.imag(tf.dtypes.cast(x,tf.complex64))\n", 190 | " real_expand = tf.expand_dims(real,-1)\n", 191 | " imag_expand = tf.expand_dims(imag,-1)\n", 192 | " concated = tf.concat([real_expand, imag_expand],-1)\n", 193 | " return tf.reshape(concated,shape=[-1,2])\n", 194 | "\n", 195 | "# Define the Channel Layer for training, as well as the channel function for testing.\n", 196 | "# A single tap channel will be implemented initially, and then a multi tap channel will be used.\n", 197 | "\n", 198 | "def reyleigh_single_tap_train (x):\n", 199 | " EbNo_train = K.variable(5.01187, dtype='float32') # coverted 7 db of EbNo\n", 200 | " noise_std = K.sqrt(1/(2*R*EbNo_train))\n", 201 | " \n", 202 | " # Create random Complex Channel with single tap\n", 203 | " h_real = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=1)\n", 204 | " h_imag = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=1)\n", 205 | " h = tf.dtypes.complex(h_real,h_imag)\n", 206 | " \n", 207 | " # Create random Complex Gaussian Noise\n", 208 | " noise_real = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=noise_std)\n", 209 | " noise_imag = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=noise_std)\n", 210 | " noise = tf.dtypes.complex(noise_real,noise_imag)\n", 211 | " \n", 212 | " return h*tf.dtypes.cast(x,tf.complex64)+noise\n", 213 | "\n", 214 | "def reyleigh_single_tap (signal,noise_std,nrow,ncol):\n", 215 | " # Create random Complex Channel with single tap\n", 216 | " channel_real = 1/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 217 | " channel_imag = 1/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 218 | " channel = channel_real + 1j*channel_imag\n", 219 | " \n", 220 | " # Create random Complex Gaussian Noise\n", 221 | " noise_real = noise_std/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 222 | " noise_imag = noise_std/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 223 | " noise = noise_real + 1j*noise_imag\n", 224 | " return np.multiply(channel,signal)+noise\n", 225 | "\n", 226 | "def reyleigh_channel(signal,noise_std,nrow,ncol,ntaps):\n", 227 | " output = np.zeros([nrow,ncol])\n", 228 | " \n", 229 | " for L in range(1,ntaps+1):\n", 230 | " channel_std = 1/(L*np.sqrt(2))\n", 231 | " channel = np.multiply(channel_std,np.random.randn(nrow,ncol))\n", 232 | " output = output + np.multiply(signal,channel)\n", 233 | "\n", 234 | " return output + noise_std*np.random.randn(nrow,ncol)\n", 235 | "\n", 236 | "def reyleigh_train_2(x):\n", 237 | " ntaps = 3\n", 238 | " noise_std = 5.01187 # coverted 7 db of EbNo\n", 239 | " nrow = 1\n", 240 | " ncol = 2*n_channel\n", 241 | " channel_std = 1/(ntaps)\n", 242 | " output = x*K.random_normal((2*n_channel,),mean=0,stddev=channel_std)\n", 243 | " \n", 244 | " for L in range(2,ntaps+1):\n", 245 | " channel = K.random_normal((2*n_channel,),mean=0,stddev=channel_std)\n", 246 | " output = output + x*channel\n", 247 | "\n", 248 | " return output + K.random_normal((2*n_channel,),mean=0,stddev=noise_std)" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 9, 254 | "metadata": {}, 255 | "outputs": [ 256 | { 257 | "name": "stderr", 258 | "output_type": "stream", 259 | "text": [ 260 | "WARNING: Logging before flag parsing goes to stderr.\n", 261 | "W0719 09:39:00.470963 140086448047936 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", 262 | "\n", 263 | "W0719 09:39:00.471649 140086448047936 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", 264 | "\n", 265 | "W0719 09:39:00.492176 140086448047936 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:4115: The name tf.random_normal is deprecated. Please use tf.random.normal instead.\n", 266 | "\n", 267 | "W0719 09:39:00.553892 140086448047936 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:2741: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.\n", 268 | "\n", 269 | "W0719 09:39:00.554906 140086448047936 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:174: The name tf.get_default_session is deprecated. Please use tf.compat.v1.get_default_session instead.\n", 270 | "\n" 271 | ] 272 | }, 273 | { 274 | "data": { 275 | "text/plain": [ 276 | "array([[ -0.9464419 , 0.68913674],\n", 277 | " [ -1.5816816 , -4.448108 ],\n", 278 | " [ -0.60854155, -2.3497143 ],\n", 279 | " [ -3.5351918 , -2.1065853 ],\n", 280 | " [ -5.954816 , -6.065078 ],\n", 281 | " [-14.254947 , -21.961578 ],\n", 282 | " [ -9.687916 , -7.810955 ],\n", 283 | " [-28.245138 , 5.808028 ],\n", 284 | " [ 13.604551 , -7.4816847 ],\n", 285 | " [ 35.678596 , 22.645836 ]], dtype=float32)" 286 | ] 287 | }, 288 | "execution_count": 9, 289 | "metadata": {}, 290 | "output_type": "execute_result" 291 | } 292 | ], 293 | "source": [ 294 | "input_signal = Input(shape=(2,))\n", 295 | "test1 = Lambda(real_to_complex)(input_signal)\n", 296 | "test2 = Lambda(reyleigh_single_tap_train)(test1)\n", 297 | "test3 = Lambda(complex_to_real)(test2)\n", 298 | "test = Model(input_signal,test1)\n", 299 | "\n", 300 | "input_signal2 = Input(shape=(1,),dtype='complex64')\n", 301 | "test4 = Lambda(complex_to_real)(input_signal2)\n", 302 | "test5 = Model(input_signal2,test4)\n", 303 | "\n", 304 | "length = 10\n", 305 | "test_in = np.reshape(np.arange(0,length*2),(length,2))\n", 306 | "test.predict(test_in)\n", 307 | "\n", 308 | "test5.predict(reyleigh_single_tap(test.predict(test_in),1,10,1))" 309 | ] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "execution_count": 10, 314 | "metadata": {}, 315 | "outputs": [ 316 | { 317 | "name": "stderr", 318 | "output_type": "stream", 319 | "text": [ 320 | "W0719 09:39:01.420792 140086448047936 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", 321 | "\n" 322 | ] 323 | } 324 | ], 325 | "source": [ 326 | "# Defined Autoencoder\n", 327 | "\n", 328 | "# Transmitter Layers\n", 329 | "input_signal = Input(shape=(M,))\n", 330 | "encoded = Dense(M, activation='relu')(input_signal)\n", 331 | "encoded1 = Dense(2*n_channel, activation='linear')(encoded)\n", 332 | "encoded2 = BatchNormalization()(encoded1)\n", 333 | "encoded3 = Lambda(lambda x:2*K.l2_normalize(x,axis=-1))(encoded2)\n", 334 | "\n", 335 | "# Reyleigh Channel Layer\n", 336 | "EbNo_train = 5.01187 # coverted 7 db of EbNo\n", 337 | "channel_in = Lambda(real_to_complex)(encoded2)\n", 338 | "channel = Lambda(reyleigh_single_tap_train)(channel_in)\n", 339 | "channel_out = Lambda(complex_to_real)(channel)\n", 340 | "\n", 341 | "# Reciever Layer\n", 342 | "decoded = Dense(256, activation='relu')(channel_out)\n", 343 | "decoded1 = Dense(M, activation='softmax')(decoded)\n", 344 | "autoencoder = Model(input_signal, decoded1)\n", 345 | "adam = Adam(lr=0.01)\n", 346 | "sgd = SGD(lr=0.03)\n", 347 | "autoencoder.compile(optimizer=adam, loss='categorical_crossentropy')" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": 11, 353 | "metadata": {}, 354 | "outputs": [ 355 | { 356 | "name": "stdout", 357 | "output_type": "stream", 358 | "text": [ 359 | "_________________________________________________________________\n", 360 | "Layer (type) Output Shape Param # \n", 361 | "=================================================================\n", 362 | "input_3 (InputLayer) (None, 4) 0 \n", 363 | "_________________________________________________________________\n", 364 | "dense_1 (Dense) (None, 4) 20 \n", 365 | "_________________________________________________________________\n", 366 | "dense_2 (Dense) (None, 2) 10 \n", 367 | "_________________________________________________________________\n", 368 | "batch_normalization_1 (Batch (None, 2) 8 \n", 369 | "_________________________________________________________________\n", 370 | "lambda_6 (Lambda) (None, 1) 0 \n", 371 | "_________________________________________________________________\n", 372 | "lambda_7 (Lambda) (None, 1) 0 \n", 373 | "_________________________________________________________________\n", 374 | "lambda_8 (Lambda) (None, 2) 0 \n", 375 | "_________________________________________________________________\n", 376 | "dense_3 (Dense) (None, 256) 768 \n", 377 | "_________________________________________________________________\n", 378 | "dense_4 (Dense) (None, 4) 1028 \n", 379 | "=================================================================\n", 380 | "Total params: 1,834\n", 381 | "Trainable params: 1,830\n", 382 | "Non-trainable params: 4\n", 383 | "_________________________________________________________________\n", 384 | "None\n" 385 | ] 386 | } 387 | ], 388 | "source": [ 389 | "# printing summary of layers and it's trainable parameters \n", 390 | "print (autoencoder.summary())" 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "execution_count": 12, 396 | "metadata": {}, 397 | "outputs": [ 398 | { 399 | "name": "stderr", 400 | "output_type": "stream", 401 | "text": [ 402 | "W0719 09:39:01.514925 140086448047936 deprecation.py:323] From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", 403 | "Instructions for updating:\n", 404 | "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" 405 | ] 406 | }, 407 | { 408 | "name": "stdout", 409 | "output_type": "stream", 410 | "text": [ 411 | "Epoch 1/50\n", 412 | "16000/16000 [==============================] - 1s 37us/step - loss: 1.3598\n", 413 | "Epoch 2/50\n", 414 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.5998\n", 415 | "Epoch 3/50\n", 416 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.3338\n", 417 | "Epoch 4/50\n", 418 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.2236\n", 419 | "Epoch 5/50\n", 420 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.0742\n", 421 | "Epoch 6/50\n", 422 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.0485\n", 423 | "Epoch 7/50\n", 424 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.1826\n", 425 | "Epoch 8/50\n", 426 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.9103\n", 427 | "Epoch 9/50\n", 428 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.1705\n", 429 | "Epoch 10/50\n", 430 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.9636\n", 431 | "Epoch 11/50\n", 432 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8501\n", 433 | "Epoch 12/50\n", 434 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.7221\n", 435 | "Epoch 13/50\n", 436 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.9637\n", 437 | "Epoch 14/50\n", 438 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8652\n", 439 | "Epoch 15/50\n", 440 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8119\n", 441 | "Epoch 16/50\n", 442 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.0082\n", 443 | "Epoch 17/50\n", 444 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8230\n", 445 | "Epoch 18/50\n", 446 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.9586\n", 447 | "Epoch 19/50\n", 448 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6732\n", 449 | "Epoch 20/50\n", 450 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8517\n", 451 | "Epoch 21/50\n", 452 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8118\n", 453 | "Epoch 22/50\n", 454 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6207\n", 455 | "Epoch 23/50\n", 456 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8253\n", 457 | "Epoch 24/50\n", 458 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.5645\n", 459 | "Epoch 25/50\n", 460 | "16000/16000 [==============================] - 0s 3us/step - loss: 0.6630\n", 461 | "Epoch 26/50\n", 462 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6738\n", 463 | "Epoch 27/50\n", 464 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6738\n", 465 | "Epoch 28/50\n", 466 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.7663\n", 467 | "Epoch 29/50\n", 468 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8116\n", 469 | "Epoch 30/50\n", 470 | "16000/16000 [==============================] - 0s 2us/step - loss: 1.0273\n", 471 | "Epoch 31/50\n", 472 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.7454\n", 473 | "Epoch 32/50\n", 474 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8462\n", 475 | "Epoch 33/50\n", 476 | "16000/16000 [==============================] - 0s 3us/step - loss: 0.6720\n", 477 | "Epoch 34/50\n", 478 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6781\n", 479 | "Epoch 35/50\n", 480 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8394\n", 481 | "Epoch 36/50\n", 482 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6252\n", 483 | "Epoch 37/50\n", 484 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8016\n", 485 | "Epoch 38/50\n", 486 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.5907\n", 487 | "Epoch 39/50\n", 488 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6373\n", 489 | "Epoch 40/50\n", 490 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6349\n", 491 | "Epoch 41/50\n", 492 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.5630\n", 493 | "Epoch 42/50\n", 494 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.5487\n", 495 | "Epoch 43/50\n", 496 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.8511\n", 497 | "Epoch 44/50\n", 498 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6925\n", 499 | "Epoch 45/50\n", 500 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6393\n", 501 | "Epoch 46/50\n", 502 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.7778\n", 503 | "Epoch 47/50\n", 504 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6458\n", 505 | "Epoch 48/50\n", 506 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.7728\n", 507 | "Epoch 49/50\n", 508 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.9364\n", 509 | "Epoch 50/50\n", 510 | "16000/16000 [==============================] - 0s 2us/step - loss: 0.6944\n" 511 | ] 512 | }, 513 | { 514 | "data": { 515 | "text/plain": [ 516 | "" 517 | ] 518 | }, 519 | "execution_count": 12, 520 | "metadata": {}, 521 | "output_type": "execute_result" 522 | } 523 | ], 524 | "source": [ 525 | "# traning auto encoder\n", 526 | "autoencoder.fit(data, data,\n", 527 | " epochs=50,\n", 528 | " batch_size=2048)" 529 | ] 530 | }, 531 | { 532 | "cell_type": "code", 533 | "execution_count": 13, 534 | "metadata": {}, 535 | "outputs": [], 536 | "source": [ 537 | "# making encoder from full autoencoder\n", 538 | "encoder = Model(input_signal, encoded3)" 539 | ] 540 | }, 541 | { 542 | "cell_type": "code", 543 | "execution_count": 14, 544 | "metadata": {}, 545 | "outputs": [], 546 | "source": [ 547 | "# making channel from full autoencoder\n", 548 | "channel_input = Input(shape=(2*n_channel,))\n", 549 | "\n", 550 | "chan = autoencoder.layers[-5](channel_input)\n", 551 | "chan = autoencoder.layers[-4](chan)\n", 552 | "chan = autoencoder.layers[-3](chan)\n", 553 | "channel_layer = Model(channel_input,chan)" 554 | ] 555 | }, 556 | { 557 | "cell_type": "code", 558 | "execution_count": 15, 559 | "metadata": {}, 560 | "outputs": [], 561 | "source": [ 562 | "# making decoder from full autoencoder\n", 563 | "encoded_input = Input(shape=(2*n_channel,))\n", 564 | "\n", 565 | "deco = autoencoder.layers[-2](encoded_input)\n", 566 | "deco = autoencoder.layers[-1](deco)\n", 567 | "decoder = Model(encoded_input, deco)" 568 | ] 569 | }, 570 | { 571 | "cell_type": "code", 572 | "execution_count": 16, 573 | "metadata": {}, 574 | "outputs": [], 575 | "source": [ 576 | "# generating data for checking BER\n", 577 | "N = 70000\n", 578 | "test_label = np.random.randint(M,size=N)\n", 579 | "test_data = []\n", 580 | "\n", 581 | "for i in test_label:\n", 582 | " temp = np.zeros(M)\n", 583 | " temp[i] = 1\n", 584 | " test_data.append(temp)\n", 585 | " \n", 586 | "test_data = np.array(test_data)" 587 | ] 588 | }, 589 | { 590 | "cell_type": "code", 591 | "execution_count": 17, 592 | "metadata": {}, 593 | "outputs": [ 594 | { 595 | "name": "stdout", 596 | "output_type": "stream", 597 | "text": [ 598 | "(4, 1, 2)\n" 599 | ] 600 | } 601 | ], 602 | "source": [ 603 | "# for plotting learned consteallation diagram\n", 604 | "\n", 605 | "scatter_plot = []\n", 606 | "for i in range(0,M):\n", 607 | " temp = np.zeros(M)\n", 608 | " temp[i] = 1\n", 609 | " scatter_plot.append(encoder.predict(np.expand_dims(temp,axis=0)))\n", 610 | "scatter_plot = np.array(scatter_plot)\n", 611 | "print (scatter_plot.shape)" 612 | ] 613 | }, 614 | { 615 | "cell_type": "code", 616 | "execution_count": 18, 617 | "metadata": {}, 618 | "outputs": [ 619 | { 620 | "data": { 621 | "image/png": "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\n", 622 | "text/plain": [ 623 | "
" 624 | ] 625 | }, 626 | "metadata": { 627 | "needs_background": "light" 628 | }, 629 | "output_type": "display_data" 630 | } 631 | ], 632 | "source": [ 633 | "# ploting constellation diagram\n", 634 | "import matplotlib.pyplot as plt\n", 635 | "scatter_plot = scatter_plot.reshape(M,2,1)\n", 636 | "plt.scatter(scatter_plot[:,0],scatter_plot[:,1])\n", 637 | "#plt.axis((-2.5,2.5,-2.5,2.5))\n", 638 | "plt.grid()\n", 639 | "plt.show()" 640 | ] 641 | }, 642 | { 643 | "cell_type": "code", 644 | "execution_count": 19, 645 | "metadata": {}, 646 | "outputs": [ 647 | { 648 | "name": "stdout", 649 | "output_type": "stream", 650 | "text": [ 651 | "(4, 1, 2)\n" 652 | ] 653 | }, 654 | { 655 | "data": { 656 | "image/png": "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\n", 657 | "text/plain": [ 658 | "
" 659 | ] 660 | }, 661 | "metadata": { 662 | "needs_background": "light" 663 | }, 664 | "output_type": "display_data" 665 | } 666 | ], 667 | "source": [ 668 | "# for plotting learned consteallation diagram after reyliegh channel\n", 669 | "\n", 670 | "scatter_plot = []\n", 671 | "for i in range(0,M):\n", 672 | " temp = np.zeros(M)\n", 673 | " temp[i] = 1\n", 674 | " scatter_plot.append(channel_layer.predict(encoder.predict(np.expand_dims(temp,axis=0))))\n", 675 | "scatter_plot = np.array(scatter_plot)\n", 676 | "print (scatter_plot.shape)\n", 677 | "\n", 678 | "# ploting constellation diagram\n", 679 | "import matplotlib.pyplot as plt\n", 680 | "scatter_plot = scatter_plot.reshape(M,2,1)\n", 681 | "plt.scatter(scatter_plot[:,0],scatter_plot[:,1])\n", 682 | "#plt.axis((-2.5,2.5,-2.5,2.5))\n", 683 | "plt.grid()\n", 684 | "plt.show()" 685 | ] 686 | }, 687 | { 688 | "cell_type": "code", 689 | "execution_count": 20, 690 | "metadata": {}, 691 | "outputs": [ 692 | { 693 | "name": "stderr", 694 | "output_type": "stream", 695 | "text": [ 696 | "/usr/local/lib/python3.6/dist-packages/numpy/core/numeric.py:538: ComplexWarning: Casting complex values to real discards the imaginary part\n", 697 | " return array(a, dtype, copy=False, order=order)\n" 698 | ] 699 | }, 700 | { 701 | "name": "stdout", 702 | "output_type": "stream", 703 | "text": [ 704 | "SNR: 0 BER: 0.7480714285714286\n", 705 | "SNR: 2 BER: 0.7503142857142857\n", 706 | "SNR: 4 BER: 0.7498\n", 707 | "SNR: 6 BER: 0.7530714285714286\n", 708 | "SNR: 8 BER: 0.7554857142857143\n", 709 | "SNR: 10 BER: 0.7592571428571429\n", 710 | "SNR: 12 BER: 0.7605142857142857\n", 711 | "SNR: 14 BER: 0.7583285714285715\n", 712 | "SNR: 16 BER: 0.7580714285714286\n", 713 | "SNR: 18 BER: 0.7622857142857142\n", 714 | "SNR: 20 BER: 0.7586428571428572\n" 715 | ] 716 | } 717 | ], 718 | "source": [ 719 | "# calculating BER\n", 720 | "# this is optimized BER function so it can handle large number of N\n", 721 | "# previous code has another for loop which was making it slow\n", 722 | "EbNodB_range = list(np.arange(0,20+1,2))\n", 723 | "ber = [None]*len(EbNodB_range)\n", 724 | "for n in range(0,len(EbNodB_range)):\n", 725 | " EbNo=10.0**(EbNodB_range[n]/10.0)\n", 726 | " noise_std = np.sqrt(1/(2*R*EbNo))\n", 727 | " noise_mean = 0\n", 728 | " no_errors = 0\n", 729 | " nn = N\n", 730 | " encoded_signal = encoder.predict(test_data) \n", 731 | " final_signal = reyleigh_single_tap(encoded_signal,noise_std,nn,1)\n", 732 | " pred_final_signal = decoder.predict(final_signal)\n", 733 | " pred_output = np.argmax(pred_final_signal,axis=1)\n", 734 | " no_errors = (pred_output != test_label)\n", 735 | " no_errors = no_errors.astype(int).sum()\n", 736 | " ber[n] = no_errors / nn \n", 737 | " print ('SNR:',EbNodB_range[n],'BER:',ber[n])" 738 | ] 739 | }, 740 | { 741 | "cell_type": "code", 742 | "execution_count": 21, 743 | "metadata": {}, 744 | "outputs": [ 745 | { 746 | "data": { 747 | "image/png": "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\n", 748 | "text/plain": [ 749 | "
" 750 | ] 751 | }, 752 | "metadata": { 753 | "needs_background": "light" 754 | }, 755 | "output_type": "display_data" 756 | } 757 | ], 758 | "source": [ 759 | "# ploting ber curve\n", 760 | "import matplotlib.pyplot as plt\n", 761 | "from scipy import interpolate\n", 762 | "plt.plot(EbNodB_range, ber, 'bo',label='Autoencoder(1,2)')\n", 763 | "plt.yscale('log')\n", 764 | "plt.xlabel('SNR Range')\n", 765 | "plt.ylabel('Block Error Rate')\n", 766 | "plt.grid()\n", 767 | "plt.legend(loc='upper right',ncol = 1)\n", 768 | "plt.show()" 769 | ] 770 | }, 771 | { 772 | "cell_type": "code", 773 | "execution_count": null, 774 | "metadata": {}, 775 | "outputs": [], 776 | "source": [] 777 | } 778 | ], 779 | "metadata": { 780 | "kernelspec": { 781 | "display_name": "Python 3", 782 | "language": "python", 783 | "name": "python3" 784 | }, 785 | "language_info": { 786 | "codemirror_mode": { 787 | "name": "ipython", 788 | "version": 3 789 | }, 790 | "file_extension": ".py", 791 | "mimetype": "text/x-python", 792 | "name": "python", 793 | "nbconvert_exporter": "python", 794 | "pygments_lexer": "ipython3", 795 | "version": "3.6.8" 796 | } 797 | }, 798 | "nbformat": 4, 799 | "nbformat_minor": 2 800 | } 801 | -------------------------------------------------------------------------------- /autoencoder_with_reiligh_1_2_and_RTN_reciever.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "Using TensorFlow backend.\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "# MIT License\n", 18 | "\n", 19 | "# Copyright (c) [2019] [Jayden Booth]\n", 20 | "\n", 21 | "# Permission is hereby granted, free of charge, to any person obtaining a copy\n", 22 | "# of this software and associated documentation files (the \"Software\"), to deal\n", 23 | "# in the Software without restriction, including without limitation the rights\n", 24 | "# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n", 25 | "# copies of the Software, and to permit persons to whom the Software is\n", 26 | "# furnished to do so, subject to the following conditions:\n", 27 | "\n", 28 | "# The above copyright notice and this permission notice shall be included in all\n", 29 | "# copies or substantial portions of the Software.\n", 30 | "\n", 31 | "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n", 32 | "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n", 33 | "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n", 34 | "# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n", 35 | "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n", 36 | "# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n", 37 | "# SOFTWARE.\n", 38 | "\n", 39 | "# Import Libraries\n", 40 | "import numpy as np\n", 41 | "import tensorflow as tf\n", 42 | "import keras\n", 43 | "from keras.layers import Input, Dense, GaussianNoise,Lambda,Dropout\n", 44 | "from keras.models import Model\n", 45 | "from keras import regularizers\n", 46 | "from keras.layers.normalization import BatchNormalization\n", 47 | "from keras.optimizers import Adam,SGD\n", 48 | "from keras import backend as K\n", 49 | "%matplotlib inline" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 2, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# Set random seeds\n", 59 | "from numpy.random import seed\n", 60 | "seed(1)\n", 61 | "from tensorflow import set_random_seed\n", 62 | "set_random_seed(3)" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 3, 68 | "metadata": {}, 69 | "outputs": [ 70 | { 71 | "name": "stdout", 72 | "output_type": "stream", 73 | "text": [ 74 | "M: 16 \t n: 1\n" 75 | ] 76 | } 77 | ], 78 | "source": [ 79 | "# Set the defining parameters\n", 80 | "# n = n_channel complex numbers (so 2n real numbers)\n", 81 | "# k = log2(M), where M is the number of messages to encode\n", 82 | "# EbNo is the energy per bit to noise power density\n", 83 | "\n", 84 | "# Encoder Parameters\n", 85 | "M = 16\n", 86 | "k = np.log2(M)\n", 87 | "n_channel = 1\n", 88 | "R = k/n_channel\n", 89 | "print('M:',M,'\\t','n:',n_channel)\n", 90 | "\n", 91 | "# Channel Parameters\n", 92 | "EbNo=10.0**(7/10.0)\n", 93 | "noise_std = np.sqrt(1/(2*R*EbNo))\n", 94 | "num_taps = 3\n", 95 | "reyleigh_std = num_taps/np.sqrt(2)" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 4, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "#generating data of size N\n", 105 | "N = 16000\n", 106 | "label = np.random.randint(M,size=N)" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 5, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "# creating one hot encoded vectors\n", 116 | "data = []\n", 117 | "for i in label:\n", 118 | " temp = np.zeros(M)\n", 119 | " temp[i] = 1\n", 120 | " data.append(temp)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 6, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "(16000, 16)\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "# checking data shape\n", 138 | "data = np.array(data)\n", 139 | "print (data.shape)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 7, 145 | "metadata": {}, 146 | "outputs": [ 147 | { 148 | "name": "stdout", 149 | "output_type": "stream", 150 | "text": [ 151 | "9 [0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]\n", 152 | "4 [0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 153 | "13 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]\n", 154 | "3 [0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 155 | "9 [0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]\n", 156 | "7 [0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 157 | "12 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]\n", 158 | "15 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]\n", 159 | "12 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]\n" 160 | ] 161 | } 162 | ], 163 | "source": [ 164 | "# checking generated data with it's label\n", 165 | "temp_check = [17,23,45,67,89,96,72,250,350]\n", 166 | "for i in temp_check:\n", 167 | " print(label[i],data[i])" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 8, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "# Functions that define the Channel. \n", 177 | "\n", 178 | "# First the encoder output must be converted to complex samples \n", 179 | "# Right now I am assuming n = 1 for simplicity\n", 180 | "\n", 181 | "def real_to_complex(x):\n", 182 | " real = x[:,0]\n", 183 | " imag = x[:,1]\n", 184 | " return tf.reshape(tf.dtypes.complex(real,imag),shape=[-1,1])\n", 185 | "\n", 186 | "def complex_to_real(x):\n", 187 | " real = tf.math.real(x)\n", 188 | " imag = tf.math.imag(tf.dtypes.cast(x,tf.complex64))\n", 189 | " real_expand = tf.expand_dims(real,-1)\n", 190 | " imag_expand = tf.expand_dims(imag,-1)\n", 191 | " concated = tf.concat([real_expand, imag_expand],-1)\n", 192 | " return tf.reshape(concated,shape=[-1,2])\n", 193 | "\n", 194 | "# Define the Channel Layer for training, as well as the channel function for testing.\n", 195 | "# A single tap channel will be implemented initially, and then a multi tap channel will be used.\n", 196 | "\n", 197 | "def reyleigh_single_tap_train (x):\n", 198 | " EbNo_train = K.variable(5.01187, dtype='float32') # coverted 7 db of EbNo\n", 199 | " noise_std = K.sqrt(1/(2*R*EbNo_train))\n", 200 | " \n", 201 | " # Create random Complex Channel with single tap\n", 202 | " h_real = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=1)\n", 203 | " h_imag = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=1)\n", 204 | " h = tf.dtypes.complex(h_real,h_imag)\n", 205 | " \n", 206 | " # Create random Complex Gaussian Noise\n", 207 | " noise_real = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=noise_std)\n", 208 | " noise_imag = 1/np.sqrt(2)*K.random_normal((n_channel,),mean=0,stddev=noise_std)\n", 209 | " noise = tf.dtypes.complex(noise_real,noise_imag)\n", 210 | " \n", 211 | " return h*tf.dtypes.cast(x,tf.complex64)+noise\n", 212 | "\n", 213 | "def reyleigh_single_tap (signal,noise_std,nrow,ncol):\n", 214 | " # Create random Complex Channel with single tap\n", 215 | " channel_real = 1/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 216 | " channel_imag = 1/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 217 | " channel = channel_real + 1j*channel_imag\n", 218 | " \n", 219 | " # Create random Complex Gaussian Noise\n", 220 | " noise_real = noise_std/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 221 | " noise_imag = noise_std/np.sqrt(2)*np.random.randn(nrow,ncol)\n", 222 | " noise = noise_real + 1j*noise_imag\n", 223 | " return np.multiply(channel,signal)+noise\n", 224 | "\n", 225 | "def reyleigh_channel(signal,noise_std,nrow,ncol,ntaps):\n", 226 | " output = np.zeros([nrow,ncol])\n", 227 | " \n", 228 | " for L in range(1,ntaps+1):\n", 229 | " channel_std = 1/(L*np.sqrt(2))\n", 230 | " channel = np.multiply(channel_std,np.random.randn(nrow,ncol))\n", 231 | " output = output + np.multiply(signal,channel)\n", 232 | "\n", 233 | " return output + noise_std*np.random.randn(nrow,ncol)\n", 234 | "\n", 235 | "def reyleigh_train_2(x):\n", 236 | " ntaps = 3\n", 237 | " noise_std = 5.01187 # coverted 7 db of EbNo\n", 238 | " nrow = 1\n", 239 | " ncol = 2*n_channel\n", 240 | " channel_std = 1/(ntaps)\n", 241 | " output = x*K.random_normal((2*n_channel,),mean=0,stddev=channel_std)\n", 242 | " \n", 243 | " for L in range(2,ntaps+1):\n", 244 | " channel = K.random_normal((2*n_channel,),mean=0,stddev=channel_std)\n", 245 | " output = output + x*channel\n", 246 | "\n", 247 | " return output + K.random_normal((2*n_channel,),mean=0,stddev=noise_std)" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": 9, 253 | "metadata": {}, 254 | "outputs": [ 255 | { 256 | "name": "stderr", 257 | "output_type": "stream", 258 | "text": [ 259 | "WARNING: Logging before flag parsing goes to stderr.\n", 260 | "W0801 18:48:38.713933 140015445403456 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", 261 | "\n", 262 | "W0801 18:48:38.715786 140015445403456 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", 263 | "\n", 264 | "W0801 18:48:38.721364 140015445403456 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", 265 | "\n", 266 | "W0801 18:48:38.821072 140015445403456 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:4115: The name tf.random_normal is deprecated. Please use tf.random.normal instead.\n", 267 | "\n", 268 | "W0801 18:48:39.071256 140015445403456 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", 269 | "\n", 270 | "W0801 18:48:39.082494 140015445403456 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:3295: The name tf.log is deprecated. Please use tf.math.log instead.\n", 271 | "\n" 272 | ] 273 | } 274 | ], 275 | "source": [ 276 | "# Defined Autoencoder\n", 277 | "\n", 278 | "# Transmitter Layers\n", 279 | "input_signal = Input(shape=(M,))\n", 280 | "encoded = Dense(M, activation='relu')(input_signal)\n", 281 | "encoded1 = Dense(2*n_channel, activation='linear')(encoded)\n", 282 | "encoded2 = Lambda(lambda x: np.sqrt(2*n_channel)*K.l2_normalize(x,axis=1))(encoded1)\n", 283 | "\n", 284 | "# Reyleigh Channel Layer\n", 285 | "EbNo_train = 5.01187 # coverted 7 db of EbNo\n", 286 | "channel_in = Lambda(real_to_complex)(encoded2)\n", 287 | "channel = Lambda(reyleigh_single_tap_train)(channel_in)\n", 288 | "channel_out = Lambda(complex_to_real)(channel)\n", 289 | "\n", 290 | "# Estimator Layer\n", 291 | "estimate = Dense(2*num_taps,activation='tanh')(channel_out)\n", 292 | "estimate1 = Dense(2*num_taps,activation='tanh')(estimate)\n", 293 | "estimate2 = Dense(2*num_taps,activation='linear')(estimate1)\n", 294 | "\n", 295 | "# Transformation Layer\n", 296 | "merge = keras.layers.concatenate([channel_out,estimate2])\n", 297 | "transform = Dense(256,activation='relu')(merge)\n", 298 | "transform = Dense(256,activation='relu')(transform)\n", 299 | "transform = Dense(256,activation='relu')(transform)\n", 300 | "transform = Dense(2*n_channel,activation='linear')(transform)\n", 301 | "\n", 302 | "# Decoder\n", 303 | "decoded = Dense(M, activation='relu')(transform)\n", 304 | "decoded1 = Dense(M, activation='softmax')(decoded)\n", 305 | "autoencoder = Model(input_signal, decoded1)\n", 306 | "adam = Adam(lr=0.01)\n", 307 | "autoencoder.compile(optimizer=adam, loss='categorical_crossentropy')" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 10, 313 | "metadata": {}, 314 | "outputs": [ 315 | { 316 | "name": "stdout", 317 | "output_type": "stream", 318 | "text": [ 319 | "__________________________________________________________________________________________________\n", 320 | "Layer (type) Output Shape Param # Connected to \n", 321 | "==================================================================================================\n", 322 | "input_1 (InputLayer) (None, 16) 0 \n", 323 | "__________________________________________________________________________________________________\n", 324 | "dense_1 (Dense) (None, 16) 272 input_1[0][0] \n", 325 | "__________________________________________________________________________________________________\n", 326 | "dense_2 (Dense) (None, 2) 34 dense_1[0][0] \n", 327 | "__________________________________________________________________________________________________\n", 328 | "lambda_1 (Lambda) (None, 2) 0 dense_2[0][0] \n", 329 | "__________________________________________________________________________________________________\n", 330 | "lambda_2 (Lambda) (None, 1) 0 lambda_1[0][0] \n", 331 | "__________________________________________________________________________________________________\n", 332 | "lambda_3 (Lambda) (None, 1) 0 lambda_2[0][0] \n", 333 | "__________________________________________________________________________________________________\n", 334 | "lambda_4 (Lambda) (None, 2) 0 lambda_3[0][0] \n", 335 | "__________________________________________________________________________________________________\n", 336 | "dense_3 (Dense) (None, 6) 18 lambda_4[0][0] \n", 337 | "__________________________________________________________________________________________________\n", 338 | "dense_4 (Dense) (None, 6) 42 dense_3[0][0] \n", 339 | "__________________________________________________________________________________________________\n", 340 | "dense_5 (Dense) (None, 6) 42 dense_4[0][0] \n", 341 | "__________________________________________________________________________________________________\n", 342 | "concatenate_1 (Concatenate) (None, 8) 0 lambda_4[0][0] \n", 343 | " dense_5[0][0] \n", 344 | "__________________________________________________________________________________________________\n", 345 | "dense_6 (Dense) (None, 256) 2304 concatenate_1[0][0] \n", 346 | "__________________________________________________________________________________________________\n", 347 | "dense_7 (Dense) (None, 256) 65792 dense_6[0][0] \n", 348 | "__________________________________________________________________________________________________\n", 349 | "dense_8 (Dense) (None, 256) 65792 dense_7[0][0] \n", 350 | "__________________________________________________________________________________________________\n", 351 | "dense_9 (Dense) (None, 2) 514 dense_8[0][0] \n", 352 | "__________________________________________________________________________________________________\n", 353 | "dense_10 (Dense) (None, 16) 48 dense_9[0][0] \n", 354 | "__________________________________________________________________________________________________\n", 355 | "dense_11 (Dense) (None, 16) 272 dense_10[0][0] \n", 356 | "==================================================================================================\n", 357 | "Total params: 135,130\n", 358 | "Trainable params: 135,130\n", 359 | "Non-trainable params: 0\n", 360 | "__________________________________________________________________________________________________\n", 361 | "None\n" 362 | ] 363 | } 364 | ], 365 | "source": [ 366 | "# printing summary of layers and it's trainable parameters \n", 367 | "print (autoencoder.summary())" 368 | ] 369 | }, 370 | { 371 | "cell_type": "code", 372 | "execution_count": null, 373 | "metadata": {}, 374 | "outputs": [ 375 | { 376 | "name": "stderr", 377 | "output_type": "stream", 378 | "text": [ 379 | "W0801 18:48:39.307630 140015445403456 deprecation.py:323] From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", 380 | "Instructions for updating:\n", 381 | "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" 382 | ] 383 | }, 384 | { 385 | "name": "stdout", 386 | "output_type": "stream", 387 | "text": [ 388 | "Epoch 1/50\n" 389 | ] 390 | } 391 | ], 392 | "source": [ 393 | "# traning auto encoder\n", 394 | "autoencoder.fit(data, data,\n", 395 | " epochs=50,\n", 396 | " batch_size=2048)" 397 | ] 398 | }, 399 | { 400 | "cell_type": "code", 401 | "execution_count": null, 402 | "metadata": {}, 403 | "outputs": [], 404 | "source": [ 405 | "# making encoder from full autoencoder\n", 406 | "encoder = Model(input_signal, encoded2)" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": null, 412 | "metadata": {}, 413 | "outputs": [], 414 | "source": [ 415 | "# making decoder from full autoencoder\n", 416 | "encoded_input = Input(shape=(2*n_channel,))\n", 417 | "\n", 418 | "deco = autoencoder.layers[-2](encoded_input)\n", 419 | "deco = autoencoder.layers[-1](deco)\n", 420 | "decoder = Model(encoded_input, deco)" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": null, 426 | "metadata": {}, 427 | "outputs": [], 428 | "source": [ 429 | "# generating data for checking BER\n", 430 | "# if you're not using t-sne for visulation than set N to 70,000 for better result \n", 431 | "# for t-sne use less N like N = 1500\n", 432 | "N = 70000\n", 433 | "test_label = np.random.randint(M,size=N)\n", 434 | "test_data = []\n", 435 | "\n", 436 | "for i in test_label:\n", 437 | " temp = np.zeros(M)\n", 438 | " temp[i] = 1\n", 439 | " test_data.append(temp)\n", 440 | " \n", 441 | "test_data = np.array(test_data)" 442 | ] 443 | }, 444 | { 445 | "cell_type": "code", 446 | "execution_count": null, 447 | "metadata": {}, 448 | "outputs": [], 449 | "source": [ 450 | "# checking generated data\n", 451 | "temp_test = 6\n", 452 | "print (test_data[temp_test][test_label[temp_test]],test_label[temp_test])" 453 | ] 454 | }, 455 | { 456 | "cell_type": "code", 457 | "execution_count": null, 458 | "metadata": {}, 459 | "outputs": [], 460 | "source": [ 461 | "# for plotting learned consteallation diagram\n", 462 | "\n", 463 | "scatter_plot = []\n", 464 | "for i in range(0,M):\n", 465 | " temp = np.zeros(M)\n", 466 | " temp[i] = 1\n", 467 | " scatter_plot.append(encoder.predict(np.expand_dims(temp,axis=0)))\n", 468 | "scatter_plot = np.array(scatter_plot)\n", 469 | "print (scatter_plot.shape)" 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": null, 475 | "metadata": {}, 476 | "outputs": [], 477 | "source": [ 478 | "# ploting constellation diagram\n", 479 | "import matplotlib.pyplot as plt\n", 480 | "scatter_plot = scatter_plot.reshape(M,2,1)\n", 481 | "plt.scatter(scatter_plot[:,0],scatter_plot[:,1])\n", 482 | "plt.axis((-2.5,2.5,-2.5,2.5))\n", 483 | "plt.grid()\n", 484 | "plt.show()" 485 | ] 486 | }, 487 | { 488 | "cell_type": "code", 489 | "execution_count": null, 490 | "metadata": {}, 491 | "outputs": [], 492 | "source": [ 493 | "# calculating BER\n", 494 | "# this is optimized BER function so it can handle large number of N\n", 495 | "# previous code has another for loop which was making it slow\n", 496 | "EbNodB_range = list(np.arange(-4,8.5,0.5))\n", 497 | "ber = [None]*len(EbNodB_range)\n", 498 | "for n in range(0,len(EbNodB_range)):\n", 499 | " EbNo=10.0**(EbNodB_range[n]/10.0)\n", 500 | " noise_std = np.sqrt(1/(2*R*EbNo))\n", 501 | " noise_mean = 0\n", 502 | " no_errors = 0\n", 503 | " nn = N\n", 504 | " noise = noise_std * np.random.randn(nn,n_channel)\n", 505 | " encoded_signal = encoder.predict(test_data) \n", 506 | " final_signal = reyleigh_channel(encoded_signal,noise_std,nn,2*n_channel,1)\n", 507 | " pred_final_signal = decoder.predict(final_signal)\n", 508 | " pred_output = np.argmax(pred_final_signal,axis=1)\n", 509 | " no_errors = (pred_output != test_label)\n", 510 | " no_errors = no_errors.astype(int).sum()\n", 511 | " ber[n] = no_errors / nn \n", 512 | " print ('SNR:',EbNodB_range[n],'BER:',ber[n])" 513 | ] 514 | }, 515 | { 516 | "cell_type": "code", 517 | "execution_count": null, 518 | "metadata": {}, 519 | "outputs": [], 520 | "source": [ 521 | "# ploting ber curve\n", 522 | "import matplotlib.pyplot as plt\n", 523 | "from scipy import interpolate\n", 524 | "plt.plot(EbNodB_range, ber, 'bo',label='Autoencoder(2,2)')\n", 525 | "plt.yscale('log')\n", 526 | "plt.xlabel('SNR Range')\n", 527 | "plt.ylabel('Block Error Rate')\n", 528 | "plt.grid()\n", 529 | "plt.legend(loc='upper right',ncol = 1)\n", 530 | "plt.show()" 531 | ] 532 | }, 533 | { 534 | "cell_type": "code", 535 | "execution_count": null, 536 | "metadata": {}, 537 | "outputs": [], 538 | "source": [] 539 | } 540 | ], 541 | "metadata": { 542 | "kernelspec": { 543 | "display_name": "Python 3", 544 | "language": "python", 545 | "name": "python3" 546 | }, 547 | "language_info": { 548 | "codemirror_mode": { 549 | "name": "ipython", 550 | "version": 3 551 | }, 552 | "file_extension": ".py", 553 | "mimetype": "text/x-python", 554 | "name": "python", 555 | "nbconvert_exporter": "python", 556 | "pygments_lexer": "ipython3", 557 | "version": "3.6.8" 558 | } 559 | }, 560 | "nbformat": 4, 561 | "nbformat_minor": 2 562 | } 563 | -------------------------------------------------------------------------------- /siso_info_and_power_transfer_with_white_noise.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "Using TensorFlow backend.\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "# MIT License\n", 18 | "\n", 19 | "# Copyright (c) [2019] [Jayden Booth]\n", 20 | "\n", 21 | "# Permission is hereby granted, free of charge, to any person obtaining a copy\n", 22 | "# of this software and associated documentation files (the \"Software\"), to deal\n", 23 | "# in the Software without restriction, including without limitation the rights\n", 24 | "# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n", 25 | "# copies of the Software, and to permit persons to whom the Software is\n", 26 | "# furnished to do so, subject to the following conditions:\n", 27 | "\n", 28 | "# The above copyright notice and this permission notice shall be included in all\n", 29 | "# copies or substantial portions of the Software.\n", 30 | "\n", 31 | "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n", 32 | "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n", 33 | "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n", 34 | "# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n", 35 | "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n", 36 | "# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n", 37 | "# SOFTWARE.\n", 38 | "\n", 39 | "# Import Relevant Libraries\n", 40 | "import numpy as np\n", 41 | "from scipy import special\n", 42 | "import tensorflow as tf\n", 43 | "from keras.layers import Input, Dense, GaussianNoise, Lambda, concatenate, Reshape\n", 44 | "from keras.models import Model\n", 45 | "from keras import regularizers\n", 46 | "from keras.layers.normalization import BatchNormalization\n", 47 | "from keras.optimizers import Adam,SGD\n", 48 | "from keras import backend as K\n", 49 | "from keras.losses import categorical_crossentropy\n", 50 | "import random as rn\n", 51 | "%matplotlib inline" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 2, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "# Set random seed for reproducing results\n", 61 | "from numpy.random import seed\n", 62 | "seed(1)\n", 63 | "from tensorflow import set_random_seed\n", 64 | "set_random_seed(3)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 3, 70 | "metadata": {}, 71 | "outputs": [ 72 | { 73 | "name": "stdout", 74 | "output_type": "stream", 75 | "text": [ 76 | "M: 16 k: 4 n: 1\n" 77 | ] 78 | } 79 | ], 80 | "source": [ 81 | "# defining parameters\n", 82 | "# define (n,k) here for (n,k) autoencoder\n", 83 | "# n = n_channel \n", 84 | "# k = log2(M) ==> so for (7,4) autoencoder n_channel = 7 and M = 2^4 = 16\n", 85 | "\n", 86 | "# Transmitter Params\n", 87 | "M = 16\n", 88 | "k = np.log2(M)\n", 89 | "k = int(k)\n", 90 | "n_channel = 1\n", 91 | "R = k/n_channel\n", 92 | "\n", 93 | "# Receiver Params\n", 94 | "power_weight_param = 1\n", 95 | "antenna_impedance = 50\n", 96 | "diode_ideality_factor = 1\n", 97 | "diode_thermal_voltage = 0.02585\n", 98 | "print ('M:',M,'k:',k,'n:',n_channel)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 4, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "# Generating data of size N\n", 108 | "N = 100000\n", 109 | "label = np.random.randint(M,size=N)" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 5, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "# Creating one hot encoded vectors\n", 119 | "data = np.zeros((N,M))\n", 120 | "\n", 121 | "for i in np.arange(0,N):\n", 122 | " data[i,label[i]] = 1" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 6, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "name": "stdout", 132 | "output_type": "stream", 133 | "text": [ 134 | "(100000, 16)\n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "# Checking data shape\n", 140 | "data = np.array(data)\n", 141 | "print(data.shape)" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 7, 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "name": "stdout", 151 | "output_type": "stream", 152 | "text": [ 153 | "9 [0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]\n", 154 | "15 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]\n", 155 | "5 [0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 156 | "4 [0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 157 | "11 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]\n", 158 | "6 [0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 159 | "10 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]\n", 160 | "7 [0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]\n", 161 | "8 [0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]\n", 162 | "10 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]\n" 163 | ] 164 | } 165 | ], 166 | "source": [ 167 | "# Check data\n", 168 | "temp_check = np.random.randint(N,size=10)\n", 169 | "\n", 170 | "for i in temp_check:\n", 171 | " print(label[i],data[i])\n", 172 | " \n", 173 | "out_data = [data,np.zeros(N)]" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 8, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "# Custom Loss Function\n", 183 | "# loss = cross entropy of one-hot message plus inverse of power times a constant\n", 184 | "# y_pred containts M values for one-hot message and then 1 value corresponding to the recieved power\n", 185 | "def power_cross_entropy(y_true,y_pred):\n", 186 | " M_pred = y_pred[:,0:M]\n", 187 | " power = y_pred[:,M]\n", 188 | " M_true = y_true\n", 189 | " e_loss = K.sum(K.categorical_crossentropy(M_true,M_pred))\n", 190 | " p_loss = K.sum(power_weight_param / power)\n", 191 | " num_inputs = K.shape(y_true)[0]\n", 192 | " \n", 193 | " return (e_loss + p_loss) / K.cast(num_inputs,'float32')\n", 194 | "\n", 195 | "# Calculate the recieved power of the signal\n", 196 | "# Derivation is shown in \"A Learning Approach to Wireless Information and Power Transfer Signal and System Design\"\n", 197 | "# by Morteza Varsteh, Enrico Piovano, and Bruno Clerckx\n", 198 | "# Input is a complex number representing recieved signal\n", 199 | "# Output is the recieved power\n", 200 | "def recieved_power(x):\n", 201 | " mag_x = K.sqrt(K.sum(K.square(x),axis=1))\n", 202 | " B = np.sqrt(antenna_impedance)/(diode_ideality_factor*diode_thermal_voltage)\n", 203 | " \n", 204 | " return tf.math.bessel_i0(mag_x)\n", 205 | " " 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 9, 211 | "metadata": { 212 | "scrolled": false 213 | }, 214 | "outputs": [ 215 | { 216 | "name": "stderr", 217 | "output_type": "stream", 218 | "text": [ 219 | "WARNING: Logging before flag parsing goes to stderr.\n", 220 | "W0801 18:56:29.952365 140576298309440 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", 221 | "\n", 222 | "W0801 18:56:29.954511 140576298309440 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", 223 | "\n", 224 | "W0801 18:56:29.960292 140576298309440 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", 225 | "\n", 226 | "W0801 18:56:30.103024 140576298309440 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:133: The name tf.placeholder_with_default is deprecated. Please use tf.compat.v1.placeholder_with_default instead.\n", 227 | "\n", 228 | "W0801 18:56:30.149303 140576298309440 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/backend/tensorflow_backend.py:4115: The name tf.random_normal is deprecated. Please use tf.random.normal instead.\n", 229 | "\n", 230 | "W0801 18:56:30.248237 140576298309440 deprecation_wrapper.py:119] From /usr/local/lib/python3.6/dist-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", 231 | "\n" 232 | ] 233 | } 234 | ], 235 | "source": [ 236 | "# Defined autoencoder\n", 237 | "\n", 238 | "# Transmitter\n", 239 | "input_signal = Input(shape=(M,))\n", 240 | "encoded = Dense(2*n_channel,activation='relu')(input_signal)\n", 241 | "encoded1 = Dense(2*n_channel,activation='linear')(encoded)\n", 242 | "encoded2 = BatchNormalization()(encoded1)\n", 243 | "encoded3 = Lambda(lambda x:1/np.sqrt(2)*K.l2_normalize(x,axis=-1))(encoded2)\n", 244 | "\n", 245 | "# Channel\n", 246 | "EbNo_train = 5.01187 # coverted 7 db of EbNo\n", 247 | "channel = GaussianNoise(np.sqrt(1/(2*R*EbNo_train)))(encoded3)\n", 248 | "\n", 249 | "# Reciever\n", 250 | "decoded = Dense(M,activation='relu')(channel)\n", 251 | "decoded1 = Dense(M,activation='softmax')(decoded)\n", 252 | "\n", 253 | "# P_del\n", 254 | "p_del = Lambda(recieved_power)(channel)\n", 255 | "p_del1 = Reshape((1,))(p_del)\n", 256 | "output = concatenate([decoded1,p_del1])\n", 257 | "\n", 258 | "# Model\n", 259 | "autoencoder = Model(input_signal,output)\n", 260 | "adam = Adam(lr=0.01)\n", 261 | "sgd = SGD(lr=0.02)\n", 262 | "autoencoder.compile(optimizer=adam,loss=power_cross_entropy)" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": 10, 268 | "metadata": {}, 269 | "outputs": [ 270 | { 271 | "name": "stdout", 272 | "output_type": "stream", 273 | "text": [ 274 | "__________________________________________________________________________________________________\n", 275 | "Layer (type) Output Shape Param # Connected to \n", 276 | "==================================================================================================\n", 277 | "input_1 (InputLayer) (None, 16) 0 \n", 278 | "__________________________________________________________________________________________________\n", 279 | "dense_1 (Dense) (None, 2) 34 input_1[0][0] \n", 280 | "__________________________________________________________________________________________________\n", 281 | "dense_2 (Dense) (None, 2) 6 dense_1[0][0] \n", 282 | "__________________________________________________________________________________________________\n", 283 | "batch_normalization_1 (BatchNor (None, 2) 8 dense_2[0][0] \n", 284 | "__________________________________________________________________________________________________\n", 285 | "lambda_1 (Lambda) (None, 2) 0 batch_normalization_1[0][0] \n", 286 | "__________________________________________________________________________________________________\n", 287 | "gaussian_noise_1 (GaussianNoise (None, 2) 0 lambda_1[0][0] \n", 288 | "__________________________________________________________________________________________________\n", 289 | "dense_3 (Dense) (None, 16) 48 gaussian_noise_1[0][0] \n", 290 | "__________________________________________________________________________________________________\n", 291 | "lambda_2 (Lambda) (None,) 0 gaussian_noise_1[0][0] \n", 292 | "__________________________________________________________________________________________________\n", 293 | "dense_4 (Dense) (None, 16) 272 dense_3[0][0] \n", 294 | "__________________________________________________________________________________________________\n", 295 | "reshape_1 (Reshape) (None, 1) 0 lambda_2[0][0] \n", 296 | "__________________________________________________________________________________________________\n", 297 | "concatenate_1 (Concatenate) (None, 17) 0 dense_4[0][0] \n", 298 | " reshape_1[0][0] \n", 299 | "==================================================================================================\n", 300 | "Total params: 368\n", 301 | "Trainable params: 364\n", 302 | "Non-trainable params: 4\n", 303 | "__________________________________________________________________________________________________\n", 304 | "None\n" 305 | ] 306 | } 307 | ], 308 | "source": [ 309 | "# printing summary of layers and it's trainable parameters \n", 310 | "print (autoencoder.summary())" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 11, 316 | "metadata": { 317 | "scrolled": false 318 | }, 319 | "outputs": [ 320 | { 321 | "name": "stderr", 322 | "output_type": "stream", 323 | "text": [ 324 | "W0801 18:56:30.468563 140576298309440 deprecation.py:323] From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", 325 | "Instructions for updating:\n", 326 | "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" 327 | ] 328 | }, 329 | { 330 | "name": "stdout", 331 | "output_type": "stream", 332 | "text": [ 333 | "Epoch 1/50\n", 334 | "100000/100000 [==============================] - 5s 52us/step - loss: 2.0557\n", 335 | "Epoch 2/50\n", 336 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.8152\n", 337 | "Epoch 3/50\n", 338 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.8040\n", 339 | "Epoch 4/50\n", 340 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7964\n", 341 | "Epoch 5/50\n", 342 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7909\n", 343 | "Epoch 6/50\n", 344 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7927\n", 345 | "Epoch 7/50\n", 346 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7911\n", 347 | "Epoch 8/50\n", 348 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7880\n", 349 | "Epoch 9/50\n", 350 | "100000/100000 [==============================] - 4s 38us/step - loss: 1.7837\n", 351 | "Epoch 10/50\n", 352 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7831\n", 353 | "Epoch 11/50\n", 354 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7860\n", 355 | "Epoch 12/50\n", 356 | "100000/100000 [==============================] - 4s 35us/step - loss: 1.7845\n", 357 | "Epoch 13/50\n", 358 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7807\n", 359 | "Epoch 14/50\n", 360 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7847\n", 361 | "Epoch 15/50\n", 362 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7839\n", 363 | "Epoch 16/50\n", 364 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7822\n", 365 | "Epoch 17/50\n", 366 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7783\n", 367 | "Epoch 18/50\n", 368 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7805\n", 369 | "Epoch 19/50\n", 370 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7859\n", 371 | "Epoch 20/50\n", 372 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7820\n", 373 | "Epoch 21/50\n", 374 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7807\n", 375 | "Epoch 22/50\n", 376 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7764\n", 377 | "Epoch 23/50\n", 378 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7822\n", 379 | "Epoch 24/50\n", 380 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7820\n", 381 | "Epoch 25/50\n", 382 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7797\n", 383 | "Epoch 26/50\n", 384 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7823\n", 385 | "Epoch 27/50\n", 386 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7800\n", 387 | "Epoch 28/50\n", 388 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7783\n", 389 | "Epoch 29/50\n", 390 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7742\n", 391 | "Epoch 30/50\n", 392 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7754\n", 393 | "Epoch 31/50\n", 394 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7777\n", 395 | "Epoch 32/50\n", 396 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7783\n", 397 | "Epoch 33/50\n", 398 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7743\n", 399 | "Epoch 34/50\n", 400 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7817\n", 401 | "Epoch 35/50\n", 402 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7764\n", 403 | "Epoch 36/50\n", 404 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7842\n", 405 | "Epoch 37/50\n", 406 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7775\n", 407 | "Epoch 38/50\n", 408 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7760\n", 409 | "Epoch 39/50\n", 410 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7771\n", 411 | "Epoch 40/50\n", 412 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7802\n", 413 | "Epoch 41/50\n", 414 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7801\n", 415 | "Epoch 42/50\n", 416 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7795\n", 417 | "Epoch 43/50\n", 418 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7769\n", 419 | "Epoch 44/50\n", 420 | "100000/100000 [==============================] - 4s 38us/step - loss: 1.7782\n", 421 | "Epoch 45/50\n", 422 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7760\n", 423 | "Epoch 46/50\n", 424 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7763\n", 425 | "Epoch 47/50\n", 426 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7753\n", 427 | "Epoch 48/50\n", 428 | "100000/100000 [==============================] - 4s 37us/step - loss: 1.7800\n", 429 | "Epoch 49/50\n", 430 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7782\n", 431 | "Epoch 50/50\n", 432 | "100000/100000 [==============================] - 4s 36us/step - loss: 1.7774\n" 433 | ] 434 | }, 435 | { 436 | "data": { 437 | "text/plain": [ 438 | "" 439 | ] 440 | }, 441 | "execution_count": 11, 442 | "metadata": {}, 443 | "output_type": "execute_result" 444 | } 445 | ], 446 | "source": [ 447 | "# traning auto encoder\n", 448 | "autoencoder.fit(data, data,\n", 449 | " epochs=50,\n", 450 | " batch_size=256)" 451 | ] 452 | }, 453 | { 454 | "cell_type": "code", 455 | "execution_count": 12, 456 | "metadata": {}, 457 | "outputs": [], 458 | "source": [ 459 | "# making encoder from full autoencoder\n", 460 | "encoder = Model(input_signal, encoded3)" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": 13, 466 | "metadata": {}, 467 | "outputs": [], 468 | "source": [ 469 | "# making decoder from full autoencoder\n", 470 | "encoded_input = Input(shape=(2*n_channel,))\n", 471 | "\n", 472 | "deco = autoencoder.layers[-5](encoded_input)\n", 473 | "deco = autoencoder.layers[-3](deco)\n", 474 | "decoder = Model(encoded_input, deco)" 475 | ] 476 | }, 477 | { 478 | "cell_type": "code", 479 | "execution_count": 14, 480 | "metadata": {}, 481 | "outputs": [], 482 | "source": [ 483 | "# generating data for checking BER\n", 484 | "N = 70000\n", 485 | "test_label = np.random.randint(M,size=N)\n", 486 | "test_data = []\n", 487 | "\n", 488 | "for i in test_label:\n", 489 | " temp = np.zeros(M)\n", 490 | " temp[i] = 1\n", 491 | " test_data.append(temp)\n", 492 | " \n", 493 | "test_data = np.array(test_data)" 494 | ] 495 | }, 496 | { 497 | "cell_type": "code", 498 | "execution_count": 15, 499 | "metadata": {}, 500 | "outputs": [ 501 | { 502 | "name": "stdout", 503 | "output_type": "stream", 504 | "text": [ 505 | "(16, 1, 2)\n" 506 | ] 507 | }, 508 | { 509 | "data": { 510 | "image/png": "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\n", 511 | "text/plain": [ 512 | "
" 513 | ] 514 | }, 515 | "metadata": { 516 | "needs_background": "light" 517 | }, 518 | "output_type": "display_data" 519 | } 520 | ], 521 | "source": [ 522 | "# for plotting learned consteallation diagram\n", 523 | "\n", 524 | "scatter_plot = []\n", 525 | "for i in range(0,M):\n", 526 | " temp = np.zeros(M)\n", 527 | " temp[i] = 1\n", 528 | " scatter_plot.append(encoder.predict(np.expand_dims(temp,axis=0)))\n", 529 | "scatter_plot = np.array(scatter_plot)\n", 530 | "print (scatter_plot.shape)\n", 531 | "\n", 532 | "# ploting constellation diagram\n", 533 | "import matplotlib.pyplot as plt\n", 534 | "scatter_plot = scatter_plot.reshape(M,2,1)\n", 535 | "plt.scatter(scatter_plot[:,0],scatter_plot[:,1])\n", 536 | "\n", 537 | "plt.grid()\n", 538 | "plt.show()" 539 | ] 540 | }, 541 | { 542 | "cell_type": "code", 543 | "execution_count": 16, 544 | "metadata": {}, 545 | "outputs": [ 546 | { 547 | "name": "stdout", 548 | "output_type": "stream", 549 | "text": [ 550 | "SNR: 0 BER: 0.6984714285714285\n", 551 | "SNR: 2 BER: 0.6264857142857143\n", 552 | "SNR: 4 BER: 0.5430857142857143\n", 553 | "SNR: 6 BER: 0.44507142857142856\n", 554 | "SNR: 8 BER: 0.3431\n", 555 | "SNR: 10 BER: 0.24198571428571428\n", 556 | "SNR: 12 BER: 0.14905714285714286\n", 557 | "SNR: 14 BER: 0.0814\n", 558 | "SNR: 16 BER: 0.03822857142857143\n", 559 | "SNR: 18 BER: 0.013971428571428572\n", 560 | "SNR: 20 BER: 0.004914285714285714\n" 561 | ] 562 | } 563 | ], 564 | "source": [ 565 | "# calculating BER\n", 566 | "# this is optimized BER function so it can handle large number of N\n", 567 | "# previous code has another for loop which was making it slow\n", 568 | "EbNodB_range = list(np.arange(0,20+1,2))\n", 569 | "ber = [None]*len(EbNodB_range)\n", 570 | "for n in range(0,len(EbNodB_range)):\n", 571 | " EbNo=10.0**(EbNodB_range[n]/10.0)\n", 572 | " noise_std = np.sqrt(1/(2*R*EbNo))\n", 573 | " noise_mean = 0\n", 574 | " no_errors = 0\n", 575 | " nn = N\n", 576 | " noise = np.random.randn(nn,2*n_channel)*noise_std\n", 577 | " encoded_signal = encoder.predict(test_data) \n", 578 | " final_signal = encoded_signal + noise\n", 579 | " pred_final_signal = decoder.predict(final_signal)\n", 580 | " pred_output = np.argmax(pred_final_signal,axis=1)\n", 581 | " no_errors = (pred_output != test_label)\n", 582 | " no_errors = no_errors.astype(int).sum()\n", 583 | " ber[n] = no_errors / nn \n", 584 | " print ('SNR:',EbNodB_range[n],'BER:',ber[n])" 585 | ] 586 | }, 587 | { 588 | "cell_type": "code", 589 | "execution_count": 17, 590 | "metadata": {}, 591 | "outputs": [ 592 | { 593 | "data": { 594 | "image/png": "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\n", 595 | "text/plain": [ 596 | "
" 597 | ] 598 | }, 599 | "metadata": { 600 | "needs_background": "light" 601 | }, 602 | "output_type": "display_data" 603 | } 604 | ], 605 | "source": [ 606 | "# ploting ber curve\n", 607 | "import matplotlib.pyplot as plt\n", 608 | "from scipy import interpolate\n", 609 | "plt.plot(EbNodB_range, ber, 'bo',label='Autoencoder')\n", 610 | "plt.yscale('log')\n", 611 | "plt.xlabel('SNR Range')\n", 612 | "plt.ylabel('Block Error Rate')\n", 613 | "plt.grid()\n", 614 | "plt.legend(loc='upper right',ncol = 1)\n", 615 | "plt.show()" 616 | ] 617 | }, 618 | { 619 | "cell_type": "code", 620 | "execution_count": null, 621 | "metadata": {}, 622 | "outputs": [], 623 | "source": [] 624 | } 625 | ], 626 | "metadata": { 627 | "kernelspec": { 628 | "display_name": "Python 3", 629 | "language": "python", 630 | "name": "python3" 631 | }, 632 | "language_info": { 633 | "codemirror_mode": { 634 | "name": "ipython", 635 | "version": 3 636 | }, 637 | "file_extension": ".py", 638 | "mimetype": "text/x-python", 639 | "name": "python", 640 | "nbconvert_exporter": "python", 641 | "pygments_lexer": "ipython3", 642 | "version": "3.6.8" 643 | } 644 | }, 645 | "nbformat": 4, 646 | "nbformat_minor": 2 647 | } 648 | --------------------------------------------------------------------------------