{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "4bcd49a4", "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "# Install HermesPy and its dependencies in the current kernel\n", "# When running on Colabs, a restart of the runtime is required afterwards\n", "\n", "import sys\n", "!{sys.executable} -m pip install --quiet hermespy" ] }, { "cell_type": "markdown", "id": "199efcaa", "metadata": {}, "source": [ "Implementing FEC codings\n", "=============================\n", "\n", "This Jupyter notebook will outline the step-by-step process of implementing a new coding scheme for the forward error correction in communication modems.\n", "The selected algorithm is a repetition encoder, since it is arguably the most basic error correction coding.\n", "\n", "As an initial step, we will import all required modules from HermesPy:" ] }, { "cell_type": "code", "execution_count": 2, "id": "cee5a390", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "from hermespy.fec import Encoder" ] }, { "cell_type": "markdown", "id": "32929b07", "metadata": {}, "source": [ "Error correcting coding steps are represented by the abstract [Encoder](../api/fec.coding.rst#hermespy.fec.coding.Encoder) interface.\n", "Each coding algorithm is represented by a class inheriting from the interface,\n", "which requires them to implement the abstract functions and properties\n", "\n", "* [encode](../api/fec.coding.rst#hermespy.fec.coding.Encoder.encode)\n", "* [decode](../api/fec.coding.rst#hermespy.fec.coding.Encoder.decode)\n", "* [bit_block_size](../api/fec.coding.rst#hermespy.fec.coding.Encoder.bit_block_size)\n", "* [code_block_size](../api/fec.coding.rst#hermespy.fec.coding.Encoder.code_block_size)\n", "\n", "Let's assume our repetition coding takes blocks of $K = 4$ data bits and repeats them $3$ times.\n", "The resulting code block size would be $N = 3K = 12$, which results in a rate of\n", "\\begin{equation}\n", "\\mathbf{R} = \\frac{K}{N} = \\frac{1}{3}\n", "\\end{equation}\n", "for the full encoding.\n", "During decoding, the repetition coding decides by majority voting which bit has been transmitted.\n", "So, our coding implementation is" ] }, { "cell_type": "code", "execution_count": 3, "id": "53c0b665", "metadata": {}, "outputs": [], "source": [ "class RepetitionCoding(Encoder):\n", " \n", " @property\n", " def bit_block_size(self) -> int:\n", " return 4\n", " \n", " @property\n", " def code_block_size(self) -> int:\n", " return 12\n", " \n", " def encode(self, data: np.ndarray) -> np.ndarray:\n", " return np.tile(data, 3)\n", " \n", " def decode(self, code: np.ndarray) -> np.ndarray:\n", " return (np.mean(np.reshape(code, (3, self.bit_block_size)), axis=0, keepdims=False) > .5).astype(int)" ] }, { "cell_type": "markdown", "id": "7c6f60ca", "metadata": {}, "source": [ "Now we can inspect our coding implementation:" ] }, { "cell_type": "code", "execution_count": 4, "id": "79ea6e6b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Our coding rate is 0.3333333333333333 with an input block size of 4 and an output block size of 12\n", "Let's assume we transmit the following data block: [1 0 1 1]\n", "After encoding the respective code block is: [1 0 1 1 1 0 1 1 1 0 1 1]\n", "After channel propagation the first bit has flipped: [0 0 1 1 1 0 1 1 1 0 1 1]\n", "But the coding can correct a single bit flip to: [1 0 1 1]\n" ] } ], "source": [ "coding = RepetitionCoding()\n", "print(f\"Our coding rate is {coding.rate} with an input block size of {coding.bit_block_size} and an output block size of {coding.code_block_size}\")\n", "\n", "data = np.random.randint(0, 2, coding.bit_block_size)\n", "print(f\"Let's assume we transmit the following data block: {data}\")\n", "\n", "code = coding.encode(data)\n", "print(f\"After encoding the respective code block is: {code}\")\n", "\n", "error_code = code.copy()\n", "error_code[0] = not error_code[0]\n", "print(f\"After channel propagation the first bit has flipped: {error_code}\")\n", "\n", "corrected_data = coding.decode(error_code)\n", "print(f\"But the coding can correct a single bit flip to: {corrected_data}\")\n" ] }, { "cell_type": "markdown", "id": "e9e4d2a7", "metadata": {}, "source": [ "We may now investigate our newly created forward error correction coding within a full Hermes simulation capaign." ] }, { "cell_type": "code", "execution_count": 5, "id": "2b59d719", "metadata": {}, "outputs": [], "source": [ "from hermespy.core import ConsoleMode, dB\n", "from hermespy.simulation import Simulation\n", "from hermespy.modem import BitErrorEvaluator, DuplexModem, RootRaisedCosineWaveform\n", "\n", "# Create a new simulation featuring a single device transmitting at 10GHz\n", "simulation = Simulation(console_mode=ConsoleMode.SILENT)\n", "device = simulation.scenario.new_device(carrier_frequency=10e9)\n", "\n", "# Configure a communication operation on the device, using our coding\n", "modem = DuplexModem()\n", "modem.waveform = RootRaisedCosineWaveform(modulation_order=4, oversampling_factor=2, num_preamble_symbols=0, num_data_symbols=10, symbol_rate=1e6)\n", "modem.encoder_manager.add_encoder(coding)\n", "modem.device = device\n", "\n", "# Run a very low-demanding simulation for demonstration purposes\n", "simulation.new_dimension('snr', dB(0, 4, 8, 16, 18, 20))\n", "simulation.add_evaluator(BitErrorEvaluator(modem, modem))\n", "simulation.num_samples = 1000\n", "\n", "result = simulation.run()" ] }, { "cell_type": "markdown", "id": "cb2ce415", "metadata": {}, "source": [ "This allows us to visualize the achieved bit error rates for given linear signal to noise ratios:" ] }, { "cell_type": "code", "execution_count": 6, "id": "f4a24f7e", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAHgCAYAAABJmwJ4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA8zklEQVR4nO3deXxU1f3/8fdkBcIkLCFhCcYICWCAsAaoCq1QrbUt9idiXSrYarXBVq1trVsRa0txQSuC4gZuX2lVbF1BUQRrCYkQAoQlIYQtkEAgJCH7cn5/4AyOSSAhmdxZXs/H4zwemTt37v3MkMu8c88599okGQEAAPihAKsLAAAAsApBCAAA+C2CEAAA8FsEIQAA4LcIQgAAwG8RhAAAgN8iCAEAAL9FEAIAAH6LIAQAAPwWQQiwiDFGs2fPtroMeKDY2FgZYzRjxgxL9j9jxgwZYxQbG2vJ/oGORBAC2onjy+ObrbCwUJ999pl+8IMfnPH1EyZM0OzZsxUREdGi/S1ZsqTR/hytsrKyrW/HbfLy8lxqPXHihNavX6+f//znZ73Nyy67zC2hcvbs2c1+xsYYRUdHt/s+O9I999yjqVOnWl0GYKkgqwsAfM0DDzygvLw82Ww2RUdHa+bMmfroo4/0ox/9SB988IFzvU6dOqmurs75+Dvf+Y4efPBBLV26VCUlJS3aV1VVlW666aZGy+vr69v+RtwoIyNDjz/+uCSpT58+uummm/TKK68oNDRUL7zwQqu398Mf/lC33Xab5syZ096lSpJuvfVWnThxotHy48ePu2V/HeXee+/VW2+9pf/85z8uy1999VUtW7ZM1dXVFlUGdByCENDOPvroI23YsMH5+MUXX1RhYaGuueYalyDUHl8ydXV1ev3111v9ui5duqiioqLJ5zp37tymM0qBgYEKCAhQbW1ts+vk5+e71L106VLt3r1bd95551kFIXd76623dPToUavL6DANDQ2EIPgNusYANzt+/LgqKytdzv5IrmOEZs+erccee0yStGfPHmfXS3uM0XB02U2cOFELFy5UYWGhDhw4IElavXq1tmzZolGjRmnNmjUqLy/X3/72N0lSr1699MILL6igoECVlZXatGmTbrjhBpdtO8ay3HXXXbr99tu1a9cuVVdX6/zzz29VjUVFRdqxY4cGDBjgsvzCCy/Uv/71L+3du1dVVVXat2+f5s+fr06dOjnXWbJkiW677TZJcum2crDZbLr99tu1detWVVZWqqCgQM8++6y6devWqhqbExUVpdraWv35z39u9FxCQoKMMZo1a5YkqXv37nr00Ue1efNmlZWVqaSkRB9++KGGDx9+xv2sXr1aq1evbrR8yZIlysvLc1l211136csvv1RRUZEqKir01Vdf6corr3RZxxijrl27aubMmc7PbMmSJZKaHyP061//Wlu3blVVVZXy8/P19NNPN+rKdfxODRkyRJ999pnKy8t14MAB/eEPfzjjewSswBkhoJ1FRESoZ8+estlsioqK0m9+8xt17dpVr732WrOvWb58uRISEnTttdfqjjvuUFFRkSTpyJEjZ9xfz549Gy2rqalRWVmZy7JFixbpyJEjeuihhxQWFuby+o8++kjLli3Ta6+9psLCQnXq1Emff/65Bg4cqKefflp5eXm66qqr9PLLL6tbt2566qmnXLZ94403qlOnTnruuedUXV2tY8eOnbHubwoMDFRMTIyKi4tdll911VXq0qWLnnnmGR09elTJycn6zW9+o5iYGE2fPl2StHjxYvXt21eXXHKJrr/++kbbXrx4sWbOnKklS5boqaeeUlxcnG677TaNHDlSF1xwQaOA2pQePXo0WlZXV6eSkhIdPnxYa9as0fTp0/XQQw+5rHP11Verrq5Ob775piTpvPPO0xVXXKE333xTeXl5io6O1i233KI1a9bo/PPP16FDh1r8mZ3O7bffrnfffVevv/66QkJC9LOf/UxvvfWWLr/8cn344YeSpOuvv14vvPCC0tLS9Nxzz0mScnNzm93m7Nmz9eCDD+qTTz7RM888o0GDBunXv/61xo4d2+hz7N69u1asWKHly5frX//6l6ZNm6ZHHnlEW7Zs0YoVK9rlPQLtydBotLa3GTNmmKZUVlaaG264odH6xhgze/Zs5+O77rrLGGNMbGxsi/a3ZMmSJvdnjDEfffRRo7rWrl1rAgICXLaxevVqY4wxv/rVr1yW//a3vzXGGHPttdc6lwUFBZkvv/zSlJaWmq5duxpJJjY21hhjzPHjx01kZGSL6s7LyzMrVqwwPXv2ND179jSJiYnm5ZdfNsYYs2DBApd1O3Xq1Oj1d999t6mvrzf9+/d3LluwYIExJ08DubQLLrjAGGPMNddc47L8kksuaXL5t9vs2bOb/Yy3b9/uXO/mm282xhiTmJjo8vqtW7eaVatWOR+HhIQYm83msk5sbKyprKw0999/v8syY4yZMWOGy7/V6tWrm/w9yMvLO+3nFhQUZDZv3uxSiyRTVlZmlixZ0uzvsuN3MTIy0lRVVZkVK1a41J+SkmKMMWbmzJmNfqeuv/5657Lg4GBz8OBB8+abb1p+nNJo326cEQLaWUpKirKzsyVJ0dHRzr+8y8rK9M4777TrviorK/XjH/+40XLHGaVvev7559XQ0NBoeVVVlbNLxOGHP/yhDh06pDfeeMO5rK6uTk899ZSWLVumSZMmuYx3evvtt5vcZ3MuvfTSRuu/9NJLjbpPqqqqnD936dJFnTt31v/+9z8FBARo5MiR2r9//2n3c9VVV+n48eP65JNPXM6cbdiwQWVlZfre977n8h6b8//+3/9TaWmpy7Ly8nLnz8uXL9fChQt19dVXO7vIEhMTlZiYqH/84x/O9Wpqapw/BwQEqFu3bjpx4oR27typUaNGnbGOlvrm59atWzcFBgbqiy++0DXXXHNW25syZYpCQ0P15JNPunQ7Pv/88/rb3/6myy+/XEuXLnUuLysrczkDWltbq7S0NJ133nlntX/AnQhCQDtLS0tzGSz9xhtvKCMjQ08//bTef//90w4ibq36+np9+umnLVr32+NIHPLz8xvVFBsbq5ycHJcvPUnavn278/mWbLs5qampuv/++xUYGKihQ4fq/vvvV/fu3V2CgiT1799fDz30kH7yk5806p5qyWUG4uPj1a1bt2a7GKOiolpU79q1a087WPro0aP69NNPNX36dGcQuvrqq1VbW6vly5c713OMV0pJSVFcXJyCgoJcttFeLr/8ct1///0aMWKEy3iqpoJwSzj+vXfu3OmyvLa2Vrt37270++AYg/ZNxcXFLRoLBXQ0ghDgZsYYrV69WnfccYfi4+O1bds2S+pobiZYe1xzqLXbKCoqcga4jz/+WDt27NAHH3yg22+/XU888YSkk2dMPvnkE/Xo0UPz5s3Tjh07VF5ern79+unll19WQMCZ53oEBASosLBQ1113XZPPt2QMVkstW7ZMS5cuVVJSkjIzMzV9+nR9+umnLgHn3nvv1cMPP6wXX3xRDzzwgI4dO6aGhgY9+eSTZ3w/xhjZbLZGywMDA10eX3jhhXr33Xe1du1apaSk6NChQ6qtrdWNN97Y7OfQ3pq7fENT9QNWIwgBHcDxl3/Xrl2bXefbZ1+stHfvXg0fPlw2m82lrsGDBzufb08ffvihPv/8c917771avHixKioqNGzYMA0aNEg33HCDXn31Vee6U6ZMafT65j673NxcTZkyRV9++aVLd5E7/Pvf/1Z1dbWuvvpqSdKgQYM0d+5cl3WmTZumzz77rNG1n7p163bGrsXi4uImu5a+fTbmyiuvVFVVlS699FKXM2w33nhjo9e29HfO8e89aNAgl7N/wcHBiouL06pVq1q0HcATMX0ecLOgoCBdcsklqq6udnYtNcUx5qS9pnW3xYcffqg+ffo4v9Slk2cefvOb36isrExr1qxp933OmzdPkZGRuvnmmyWdOqvw7bMIt99+e6PXOj67b3eX/etf/1JQUJAeeOCBRq8JDAxs8VW8W6KkpEQrV67U9OnT9bOf/UzV1dX697//7bJOfX19o/czbdo0xcTEnHH7ubm5Gjx4sCIjI53Lhg8frgsuuKDRPowxLmeKYmNjdcUVVzTaZnl5eYt+31atWqXq6mr99re/dVn+y1/+Ut26dXMZLwZ4G84IAe3ssssuc545iYqK0rXXXquEhATNnTu30ZT2b3KMK/rrX/+qZcuWqba2Vu+9916zFz6UToas5ro73nnnndO+9nSee+453XLLLVq6dKlGjx6tPXv2aNq0abrwwgt1++23N3mV5bZasWKFtmzZot/97ndauHChduzYoV27dumxxx5Tv379VFpaqiuvvFLdu3dv9FrHZ/fUU09p5cqVqq+v1z//+U+tXbtWzz77rO69916NGDFCH3/8sWpraxUfH6+rrrpKt99+u95+++0z1jZt2rQm3/Mnn3yiw4cPOx//85//1Ouvv66UlBStXLmy0RXC33//fc2ePVsvvfSS/ve//2nYsGG67rrrTjtt3eGll17S7373O61cuVIvvviioqKidOuttyorK0vh4eHO9T744APdddddWrFihf7v//5PUVFRmjVrlnbt2qWkpKRGn9uUKVN055136uDBg8rLy1NaWlqjfRcVFWnu3Ll68MEHtWLFCr377rsaNGiQUlJSlJaWdtpLQwDewPKpazSaL7Smps9XVFSYjRs3mltuuaXR+t+ePi/J3HfffWb//v2mrq7ujFPpTzd9/puvddQ1evToRttYvXq12bJlS5Pb79Wrl3nxxRfN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YYJsNpuWL1+umpoajRs3TrfeeqvmzZt3xu3Gx8fr4osv1vr1691ZPuBz4uLi1KdPH5djsrS0VOvXr9eECRMknTyj9P7772vbtm0aPXq0HnzwQT322GNn3Pbo0aM1evRojkvgWxxjeo4dOybp5LESEhLichzu3LlTe/fudR6HMTExWr58ud577z2NGDFCL7zwgv7+97+fcV+XXnqpzjnnnDYfh9x0tZ1ERkYqKChIhYWFLssLCws1ePBgTZkyRYMHD9all16qQ4cOSZLuvfderVixotG23njjDdXX1ysoKEidOnXSe++9p7lz53bI+wB8Re/evSWpyWPS8dy1116rgIAA/fKXv1R1dbW2bdummJgYPfvss42297///U8NDQ0KCQlRSEiIFi9erFdffdX9bwTwEjabTU8++aT++9//KisrS9LJ47C6ulolJSUu637zOPz1r3+t3Nxc/f73v5ckZWdna9iwYfrTn/7UaB8HDhyQdHLcUUBAgP785z/riy++aFPdBKEOMmTIEO3fv98ZgiRp3bp1Ta575513atWqVQoMDNTAgQM1f/58vfrqq7rmmms6qlzALwwZMkSbN292ubx/c8fl1Vdfre3btys4OFhDhw7VggULVFxcrHvuuaejygU82sKFCzV06FBdeOGFrXrdkCFDGp3Vae44vOiii1RWVqbQ0FAlJyfr6aef1rFjx5r846WlCELtpKioSHV1dYqOjnZZHh0drYKCglZtq6CgQLm5uZJOJmO73a5ly5bp/vvvdy4HcHqO4+7bx2B0dLQ2bdrU6u3t37/fefzt2LFDAwYM0F/+8hfL75MEeIIFCxboRz/6kSZOnKj8/Hzn8oKCAoWGhioiIsLlrNDZfDdKUl5ennM727Zt07hx43Tfffe1KQgxRqid1NbWasOGDZo8ebJzmc1m0+TJk7Vu3Tpt375d/fv3d54KlKTx48e3aNv19fWSpM6dO7dv0YAPy8vL06FDh1yOSbvdrnHjxjn/2ty+fbuGDx/uMousNcdlcHAwl7aA31uwYIF++tOf6uKLL9aePXtcntuwYYNqampcjsOEhATFxsa6HIfJyckur2vNcdge342WjzL3lTZ9+nRTWVlpbrjhBjN48GDz7LPPmmPHjpmoqChjs9nM1q1bzcqVK83w4cPNhRdeaNLT05ucNTZjxgwTHR1t+vTpYyZOnGg2b95sduzYYQIDAy1/jzSaJ7WwsDCTlJRkkpKSjDHG3HHHHSYpKcn079/fSDJ//OMfzbFjx8yPf/xjM3ToUPPOO++Y3NxcExoa6nz94cOHzSuvvGKGDBliLrvsMpOdnd3krLGLL77YREdHm379+pkf/OAHZv/+/ebTTz+1/DOg0axsCxcuNMXFxWbixIkmOjra2Tp16uRcZ9GiRWbPnj3mu9/9rhk1apT58ssvzZdfful8vn///qaqqso88sgjJiEhwVxzzTXm4MGDTc4ai4+PN9HR0eacc84x06ZNMyUlJebFF19s6/uw/oP0pTZr1iyzZ88eU1VVZVJTU01ycrLzufj4eLN27VpTVVVlduzYYS655JImg5BDfX29yc/PN2+88YaJi4uz/L3RaJ7WHP85ftuSJUuc68yZM8ccOnTIVFZWmk8++cTEx8e7bGPcuHEmIyPDVFVVmY0bN5qf/vSnTQYhh9raWrNv3z6zePFiExkZaflnQKNZ2ZozY8YM5zqhoaHm6aefNkePHjUnTpwwb7/9tomOjnbZzuWXX26ys7NNZWWlWbNmjZk5c2aTQcihpqbG5ObmmkceecR06dKlTe/B9vUPAAAAfocxQgAAwG8RhAAAgN8iCAEAAL9FEAIAAH6LIAQAAPwWQQgAAPgtghAAAPBbBCEAAOC3CEIAAMBvEYQA+IzIyEgtWrRIe/fuVVVVlQ4dOqQVK1boO9/5jqSTN2I1xmjcuHEur3viiSe0evVq5+PZs2fLGCNjjOrq6rRv3z4tXrxY3bt379D3A8D9gqwuAADay9tvv62QkBDNmDFDu3fvVnR0tCZPnqyePXs616msrNS8efP03e9+97Tb2rp1q6ZMmaLAwEANGTJEL730kiIiIvSzn/3Mze8CQEciCAHwCREREZo4caImTZqktWvXSpL27dun9PR0l/Wee+453Xrrrbrsssv00UcfNbu9uro6FRYWSpIOHjyoN998UzfeeKP73gAAS9A1BsAnnDhxQmVlZbriiisUEhLS7Hp5eXl69tlnNXfuXNlsthZtOzY2Vpdeeqlqamraq1wAHoIgBMAn1NfXa+bMmZoxY4aOHz+u//73v/rrX/+qYcOGNVr34YcfVlxcnK677rpmtzds2DCVlZWpoqJCe/bs0dChQzVv3jx3vgUAFiAIAfAZy5cvV9++ffWTn/xEK1as0He/+11t3LhRM2bMcFmvqKhIjz32mB566CEFBwc3ua2dO3dqxIgRGjt2rP7+979rxYoVWrBgQUe8DQAdiCAEwKdUV1dr1apVevjhh3XBBRdo6dKlmjNnTqP15s+fr86dOyslJaXJ7dTU1Cg3N1dZWVm65557VF9fr9mzZ7u7fAAdjCAEwKdt27ZNYWFhjZaXl5frL3/5i+677z7Z7fYzbufhhx/W73//e/Xp08cdZQKwCEEIgE/o0aOHPv30U1133XUaNmyYzj33XE2bNk1//OMf9Z///KfJ1zz33HMqKSnRtddee8btp6amavPmzbr33nvbu3QAFiIIAfAJJ06c0Pr163XnnXdq7dq12rp1q/7yl7/o+eef12233dbka+rq6vTAAw+oc+fOLdrHE088oZtuukkxMTHtWToAC9kkGauLAAAAsAJnhAAAgN8iCAEAAL9FEAIAAH6LIAQAAPwWQQgAAPgtghAAAPBbBCEAAOC3CEIAAMBvEYQAAIDfIggBAAC/RRACAAB+6/8DiMDS5/FqHfUAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "_ = result.plot()\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.12 ('hermes')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.1" }, "vscode": { "interpreter": { "hash": "15324ae639e283979e39f32b76ef84dde816ef5cb4e81fc04e688fd3d2128060" } } }, "nbformat": 4, "nbformat_minor": 5 }