From 0eb29929c79d6279b46e1557e6851b9b2585d2a0 Mon Sep 17 00:00:00 2001 From: Julius <julius.zocher@rwth-aachen.de> Date: Tue, 28 Nov 2023 17:35:49 +0100 Subject: [PATCH 01/23] initial structure --- .gitignore | 3 + Dockerfile | 6 +- .../Quickstart.ipynb | 57 ++++++++++----- Excercise_1/main.ipynb | 48 +++++++++++++ Excercise_2/main.ipynb | 69 +++++++++++++++++++ Excercise_3/main.ipynb | 69 +++++++++++++++++++ environment.yml | 4 +- requirements.txt | 1 - 8 files changed, 231 insertions(+), 26 deletions(-) rename Quickstart.ipynb => Excercise_1/Quickstart.ipynb (93%) create mode 100644 Excercise_1/main.ipynb create mode 100644 Excercise_2/main.ipynb create mode 100644 Excercise_3/main.ipynb delete mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index 5751acb..06caacc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ __pycache__/ # Jupyter .ipynb_checkpoints + +# pycharm +.idea \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index bf7b0ec..9fdc660 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,11 +2,7 @@ ARG BASE_IMAGE=registry.git.rwth-aachen.de/jupyter/profiles/rwth-courses:latest FROM ${BASE_IMAGE} -# Install packages via requirements.txt -ADD requirements.txt . -RUN pip install -r requirements.txt - -# .. Or update conda base environment to match specifications in environment.yml +# Update conda base environment to match specifications in environment.yml ADD environment.yml /tmp/environment.yml # All packages specified in environment.yml are installed in the base environment diff --git a/Quickstart.ipynb b/Excercise_1/Quickstart.ipynb similarity index 93% rename from Quickstart.ipynb rename to Excercise_1/Quickstart.ipynb index c38cd0b..bd022ba 100644 --- a/Quickstart.ipynb +++ b/Excercise_1/Quickstart.ipynb @@ -19,11 +19,13 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, "source": [ "## Markdown\n", "\n", - "You can specify the cell type which is either _Code_ or _Markdown_. \n", + "ou can specify the cell type which is either _Code_ or _Markdown_. \n", "\n", "### Lists\n", "\n", @@ -58,15 +60,6 @@ "## Python" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Hello world!\")" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -78,14 +71,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello world!\n" + ] + } + ], "source": [ - "import numpy as np\n", - "\n", - "a = np.array([0, 1, -5])\n", - "a" + "print(\"Hello world!\")" ] }, { @@ -97,6 +95,29 @@ "Nice matplotlib [tutorial](https://matplotlib.org/tutorials/introductory/usage.html#sphx-glr-tutorials-introductory-usage-py)" ] }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0, 1, -5])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "\n", + "a = np.array([0, 1, -5])\n", + "a" + ] + }, { "cell_type": "code", "execution_count": null, @@ -264,7 +285,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.9.18" } }, "nbformat": 4, diff --git a/Excercise_1/main.ipynb b/Excercise_1/main.ipynb new file mode 100644 index 0000000..daab14b --- /dev/null +++ b/Excercise_1/main.ipynb @@ -0,0 +1,48 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# main" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.18" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Excercise_2/main.ipynb b/Excercise_2/main.ipynb new file mode 100644 index 0000000..d8e9a62 --- /dev/null +++ b/Excercise_2/main.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# main" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'pandas'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m\n", + "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'pandas'" + ] + } + ], + "source": [ + "import pandas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.18" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Excercise_3/main.ipynb b/Excercise_3/main.ipynb new file mode 100644 index 0000000..d8e9a62 --- /dev/null +++ b/Excercise_3/main.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# main" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'pandas'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m\n", + "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'pandas'" + ] + } + ], + "source": [ + "import pandas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.18" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/environment.yml b/environment.yml index c22af46..44bf026 100644 --- a/environment.yml +++ b/environment.yml @@ -1,5 +1,5 @@ -name: base +name: DEV channels: - conda-forge dependencies: - - bokeh==2.4.0 + - pandas==2.0.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index fb6c7ed..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pandas -- GitLab From 75244d0f6a272fafbdff5e84a3f3556c9c1cabcb Mon Sep 17 00:00:00 2001 From: Julius <julius.zocher@rwth-aachen.de> Date: Wed, 28 Feb 2024 09:46:23 +0100 Subject: [PATCH 02/23] test1 --- .gitignore | 2 +- ...Ex2_Battery_Optimization_noSolutions.ipynb | 462 +++++++++++++++ Excercise_1/Quickstart.ipynb | 293 ---------- Excercise_1/main.ipynb | 48 -- .../2023_12_01_DEV_UE2_A2_v1.0_students.ipynb | 539 ++++++++++++++++++ Excercise_2/main.ipynb | 69 --- Excercise_2/measurement_data.xlsx | Bin 0 -> 8737 bytes Excercise_3/340px-English-slf(1).png | Bin 0 -> 10402 bytes Excercise_3/Cryptography.ipynb | 483 ++++++++++++++++ Excercise_3/main.ipynb | 69 --- Excercise_3/shakethatpear.txt | 33 ++ 11 files changed, 1518 insertions(+), 480 deletions(-) create mode 100644 Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb delete mode 100644 Excercise_1/Quickstart.ipynb delete mode 100644 Excercise_1/main.ipynb create mode 100644 Excercise_2/2023_12_01_DEV_UE2_A2_v1.0_students.ipynb delete mode 100644 Excercise_2/main.ipynb create mode 100644 Excercise_2/measurement_data.xlsx create mode 100644 Excercise_3/340px-English-slf(1).png create mode 100644 Excercise_3/Cryptography.ipynb delete mode 100644 Excercise_3/main.ipynb create mode 100644 Excercise_3/shakethatpear.txt diff --git a/.gitignore b/.gitignore index 06caacc..c2d867e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ __pycache__/ .ipynb_checkpoints # pycharm -.idea \ No newline at end of file +.idea diff --git a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb new file mode 100644 index 0000000..915d5e0 --- /dev/null +++ b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb @@ -0,0 +1,462 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "52b6c1bb", + "metadata": {}, + "source": [ + "# DEV Excercise 3\n", + "Task 2 - Battery storage optimization\n", + "\n", + "In this task, an energy system consisting of a building with an electrical load (e.g. household appliances), PV system, battery storage and electricity grid connection is considered.\n", + "24 time steps are considered, corresponding to the 24 hours of a day.\n", + "Complete the code snippets where needed at places market with \"!!!\"." + ] + }, + { + "cell_type": "markdown", + "id": "6e26b8e3", + "metadata": {}, + "source": [ + "Definition of the individual components:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "f93f1b55", + "metadata": {}, + "outputs": [], + "source": [ + "# Time series of electrical load [kW]\n", + "el_demand_kW = [0.3, 0.4, 0.3, 0.3, 0.3, 0.3, 0.6, 0.7, 0.5, 0.4, 0.4, 0.7, 1.1, 0.8, 0.3, 0.3, 0.3, 0.3, 0.5, 0.7, 1.2, 1, 0.8, 0.4]\n", + "\n", + "# Time series for costs of electricity from the grid [€/kWh]\n", + "c_euro_kWh = [0.24, 0.32, 0.26, 0.25, 0.23, 0.32, 0.33, 0.35, 0.32, 0.32, 0.31, 0.28, 0.24, 0.33, 0.22, 0.27, 0.32, 0.32, 0.35, 0.32, 0.3, 0.33, 0.32, 0.31]\n", + "\n", + "# PV system\n", + "pv_pu = [0, 0, 0, 0, 0, 0, 0.1, 0.3, 0.6, 0.7, 0.8, 0.9, 1, 1, 0.9, 0.8, 0.7, 0.6, 0.3, 0.1, 0, 0, 0, 0] # Generation time series per unit [p.u.]\n", + "pv_kWp = 8 # peak power [kW]\n", + "\n", + "# Battery storage system\n", + "E_bat_kWh = 3 # capacity [kWh]\n", + "P_bat_max_charge_kW = 1 # max charging power [kW] (charging efficiency of 100 % is assumed)\n", + "P_bat_max_discharge_kW = 1 # max discharging power [kW] (discharging efficiency of 100 % is assumed)\n" + ] + }, + { + "cell_type": "markdown", + "id": "d8d3f3bb", + "metadata": {}, + "source": [ + "# Task 2 a)\n", + "Plot the electrical demand, the electricity price as well as the PV generation for a 8 kWp plant. Use the python library matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "8f2b2111", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# define the function\n", + "def plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp):\n", + " # !!! insert function\n", + " plt.plot(el_demand_kW)\n", + " plt.plot(c_euro_kWh)\n", + " plt.plot(pv_pu)\n", + " plt.plot(pv_kWp)\n", + " plt.show()\n", + " pass\n", + "\n", + "# Call the function\n", + "plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp)" + ] + }, + { + "cell_type": "markdown", + "id": "40fc921d", + "metadata": {}, + "source": [ + "# Task 2 b)\n", + "Calculate the costs of electricity supply assuming the PV plant and battery storage system are not operating. (Using numpy might be helpfull)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "69488a00", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The total electricity costs are 3.9 €\n" + ] + } + ], + "source": [ + "# define function\n", + "def get_total_costs(energy, costs):\n", + " c_total = np.dot(np.array(energy),np.array(costs)) # !!! <-- insert calculation\n", + " return c_total\n", + "\n", + "# call function\n", + "c_total = get_total_costs(el_demand_kW, c_euro_kWh)\n", + "print(f\"The total electricity costs are {round(c_total,2)} €\")" + ] + }, + { + "cell_type": "markdown", + "id": "9d4e20d6", + "metadata": {}, + "source": [ + "# Task 2 c)\n", + "Calculate the costs of electricity considering a 8 kWp PV plant, but no battery storage system. Assume that no income is generated by feeding the PV generated electricity into the grid." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "e410b81f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The total electricity costs are -16.82 €\n" + ] + } + ], + "source": [ + "# calculate residuum\n", + "residuum_kW = np.array(el_demand_kW) - pv_kWp*np.array(pv_pu) # !!! <-- insert calculation \n", + "\n", + "# call cost calculating function\n", + "c_total_residuum = get_total_costs(residuum_kW, c_euro_kWh)\n", + "print(f\"The total electricity costs are {round(c_total_residuum,2)} €\")" + ] + }, + { + "cell_type": "markdown", + "id": "e432595f", + "metadata": {}, + "source": [ + "# Task 2d)\n", + "In the following, an optimization problem is set up to optimize the operation of the battery in such a way that the electricity supply for the house is as cost-effective as possible." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "eedebac7", + "metadata": {}, + "outputs": [], + "source": [ + "# Import of necessary packages\n", + "from pulp import LpProblem, LpVariable, lpSum, LpMinimize\n", + "\n", + "# Create a new model\n", + "def optimze_battery_operation(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh):\n", + " model = LpProblem(\"charging_optimization\", LpMinimize)\n", + "\n", + " # Decision Variables\n", + " buy = LpVariable.dicts(\"buy\", range(24), lowBound=0) # The amount of electricity (in kW) bought from the grid at time t\n", + " soc = LpVariable.dicts(\"soc\", range(25), lowBound=0, upBound=E_bat_kWh) # The State of Charge (in kWh) of the battery at time t\n", + " discharge = LpVariable.dicts(\"discharge\", range(24), lowBound=0, upBound=P_bat_max_discharge_kW) # Discharge rate (in kW) at time t\n", + " charge = LpVariable.dicts(\"charge\", range(24), lowBound=0, upBound=P_bat_max_charge_kW) # Charge rate (in kW) at time t\n", + " feedin = LpVariable.dicts(\"feedin\", range(24), lowBound=0) # The amount of electricity (in kW) sold to the grid at time t\n", + " consumed_pv = LpVariable.dicts(\"consumed_pv\", range(24), lowBound=0) # The amount of electricity (in kW) consumed directly from PV at time t\n", + "\n", + " # Objective Function\n", + " model += lpSum(c_euro_kWh[t] * buy[t] for t in range(24))\n", + "\n", + " # Constraints\n", + " model += soc[0] == E_bat_kWh/2\n", + " model += soc[23] == E_bat_kWh/2\n", + "\n", + " # Energy balance for consumed electricity\n", + " for t in range(24):\n", + " model += el_demand_kW[t] == consumed_pv[t] + buy[t] + discharge[t]\n", + "\n", + " # Energy balance for generated electricity\n", + " for t in range(24):\n", + " model += pv_kWp * pv_pu[t] == charge[t] + feedin[t] + consumed_pv[t]\n", + "\n", + " # State of Charge\n", + " for t in range(23):\n", + " model += soc[t+1] == soc[t] + charge[t] - discharge[t]\n", + "\n", + " # Solve the optimization problem\n", + " model.solve()\n", + "\n", + " return model, buy, soc, feedin" + ] + }, + { + "cell_type": "markdown", + "id": "fe89f489", + "metadata": {}, + "source": [ + "Calculate the costs of electricity considering a 8 kWp PV plant and 3 kWh battery storage system. Assume that no income is generated by feeding the PV generated electricity into the grid. Plot the resulting state of charge (SOC) and buy time series and compare them to the other time series.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "4e6625bc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The total electricity costs are 0.55 €\n", + "The total electricity costs are 0.55 €\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD4CAYAAAD8Zh1EAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAAAphUlEQVR4nO3deXxb1Zn/8c8j71vsJJazeMme2EnshJCFHUo39rQFSpJuMDAZOu20fU1Lh9IO09JCoQtl63R+MKXQDlAKdBhaQoECZSsEEpPYzkZMFsfKYseL7MSxHdvn98fVTYxix7It6V5Jz/v1ygtbupYehPlyOM8554oxBqWUUrHP43QBSimlwkMDXSml4oQGulJKxQkNdKWUihMa6EopFSeSnXrj/Px8M3XqVKfeXimlYtL69esPGmO8Az3nWKBPnTqVdevWOfX2SikVk0Rk92DP6ZSLUkrFCQ10pZSKExroSikVJzTQlVIqTmigK6VUnBgy0EUkXUTeEZGNIrJJRH4wwDVpIvK4iNSKyFoRmRqRapVSSg0qlBF6F3C+MWYBsBC4QEROC7rmWqDFGDMT+AVwR1irVEopNaQh16Eb63zdQ4FvUwJ/gs/cXQ58P/D1k8B9IiJGz+ZVSkWRMYaXtjRQVd867J+dlJfByqUl4S8qikLaWCQiScB6YCbwS2PM2qBLCoE9AMaYHhHxA+OBg0GvsxpYDVBSEtsfnFLKPYwxvLD5AHf/dTub97UBIDKcn7f+euaMfErGZ0agwugIKdCNMb3AQhHJA/5XROYbY2qG+2bGmPuB+wEWL16so3el1Kj09QWC/KXtbNnXxrT8LH5+5QKWL5xMclLoaz6q6lu57L43qfb54z/QbcaYVhF5BbgA6B/oPqAYqBeRZCAXaApblUop1Y8V5Pu566/b2bq/nWn5Wdz52QVctmB4QW6bMzGHlCSh2ufn4opJEag4OoYMdBHxAkcDYZ4BfJwTm57PAF8C3gKuAF7W+XOlVLj19Rme37Sfu1+ygnx6fha/uGoBl1aMLMhtaclJzJmYQ7WvNXzFOiCUEfok4OHAPLoH+IMx5s8icguwzhjzDPBr4HciUgs0AysiVrFSKuH09Rn+smk/d/91O9sOtDPdm8VdVy3k0gWTSfIMY7L8JMoL83i2ai/GGGQ4E/AuEsoqlyrglAEev7nf153AleEtTSmV6Pr6DM/V7Oeel6wgn+HN4u4VC7mkInxBbisvzOWxd+qoa+5gyvissL52tDh2fK5SSg3lut+u4+WtDcwsyI5YkNvKC3MBqPb5NdCVUiqc2jqP8vLWBr50+hRuvnRexILcNntiNqlJHqp9fi6pmBzR94oUPctFKeVKNT4/AOeXTYh4mEO/xmi9P+LvFSka6EopV7KD1Z4KiYbyolyqfX5idZGeBrpSypWqfX4K8zIYl5UatfcsL8ylvbOH3U0dUXvPcNJAV0q5Uo3PH9XROXy4MRqLNNCVUq7jP3KUXU0dlBdFN9BnT8ghNclzbP4+1migK6VcZ5Mv+vPnAKnJHkon5VAVo41RDXSllOtUORTo9nvW7PXT1xd7jVENdKWU61T7/BSNzWBsFBuitmON0ebYa4xqoCulXKe6PvoNUZs9bx+LjVENdKWUq/g7jlLXHP2GqG32hBxSk2OzMaqBrpRylZq9zs2fA6QkeSibmDOi29g5TQNdKeUq9gqT+ZOdCXSwpl02+dpirjGqga6UcpUan5/icc40RG3lhbm0d/Wwq+mwYzWMhAa6UspVqnytjk232MoL84DYa4xqoCulXKO1o5s9zUeOBapTZk3IJjXZE3MnL2qgK6Vco8bXBjjXELWlJHmYO2mMjtCVUmqkqgI3aZ5fOMbZQrD+o7Jpb2w1RjXQlVKuUePzUzIuk7xM5xqitvLCXA519bAzhhqjGuhKKdeocnCHaDB7Y1MsbTDSQFdKuULL4W7qW444tkM02KyCbNKSPTF18qIGulLKFaodPGFxIMlJHuZOjq3GqAa6UsoV7OB0codosPLCXDb5Yuco3SEDXUSKReQVEdksIptE5OsDXHOeiPhFZEPgz82RKVcpFa9qfH6mjM8kNzPF6VKOmV+Yy+HuXnYcjI3GaHII1/QA3zTGVIpIDrBeRF40xmwOuu51Y8wl4S9RKZUIqur9LCzJc7qMD6no1xidWZDtcDVDG3KEbozZZ4ypDHzdDmwBCiNdmFIqcTQf7sbXeoQKl8yf22Z6s0lPiZ3G6LDm0EVkKnAKsHaAp08XkY0i8pyIzBvk51eLyDoRWdfY2Dj8apVSccltDVFbcmDHaKwsXQw50EUkG3gK+IYxpi3o6UpgijFmAXAv8PRAr2GMud8Ys9gYs9jr9Y6wZKVUvLEDc57LAh2O32O0NwYaoyEFuoikYIX5I8aYPwY/b4xpM8YcCny9BkgRkfywVqqUilvV9X6mjs8kN8M9DVFbeVEeHd297Dx4yOlShhTKKhcBfg1sMcbcOcg1EwPXISJLA6/bFM5ClVLxq9rnZ74LR+dwfBooFtajhzJCPxP4AnB+v2WJF4nI9SJyfeCaK4AaEdkI3AOsMMa4//9PlFKOazrUZTVEXbJDNNgMb1bMNEaHXLZojHkDkCGuuQ+4L1xFKaUSx7ENRS4doScneZg3OTcmGqO6U1Qp5agalwc6BBqjvjbXN0Y10JVSjqqq9zMtP4sx6e5riNrKC3M5crSXHY3uboxqoCulHFXj4oaozT4B0u2NUQ10pZRjDh7qYq+/03U7RIPN8GaTkZLk+saoBrpSyjFub4jakjzCvMnu3zGqga6UckxNvR3ozt9DdCjzA/cYdXNjVANdKeWYKp+f6flZ5Li4IWqrKLIaox+4uDGqga6UckwsNERtx3aMungeXQNdKeWIxvYu9vk7XbtDNNh0bzaZqUmuXumiga6UckQsbCjqz26MaqArpVSQap8fEZg32f0NUZvVGPXT09vndCkD0kBXSjnC3iEaCw1RW0VRLp1H+/ig0Z33GNVAV0o5osbnd/2GomB2Y7SqvtXZQgahga6UirqG9k72t3XGzPy5bVp+NlmpSa7dYKSBrpSKuhqX3kN0KFZjNNe1jVENdKVU1FXXt1kN0RgLdLAao5v3tbmyMaqBrpSKumpfK9Pzs8hOG/IeO65jN0ZrXbhjVANdKRV11T4/FUV5TpcxIvOPNUbdN+2iga6UiqqGtk4OtHXFXEPUNj0/y7WNUQ10pVRUVcdoQ9Tm8QjzCt3ZGNVAV0pFVVV97O0QDVZRmMvmve5rjGqgK6WiqsbnZ4Y3m6wYbIjayoty6erpY3uDuxqjGuhKqaiqjsEdosHmu/QoXQ10pVTUHGjrpKE9dhuitmnjrSWXbptHHzLQRaRYRF4Rkc0isklEvj7ANSIi94hIrYhUiciiyJSrlIpl9oi2PEbOQB+Mx6VH6YYyQu8BvmmMmQucBnxFROYGXXMhMCvwZzXwq7BWqZSKC1U+Px6BuZNityFqqyiydowedVFjdMhAN8bsM8ZUBr5uB7YAhUGXLQd+ayxvA3kiMins1SqlYlo8NERt8wtz6e7p4/0D7U6Xcsyw5tBFZCpwCrA26KlCYE+/7+s5MfQRkdUisk5E1jU2Ng6zVKVULDPGUO3zx/x0i23J1HGIwPObDjhdyjEhB7qIZANPAd8wxrSN5M2MMfcbYxYbYxZ7vd6RvIRSKkYdaOuisb0rZjcUBZucl8E5s7w8/m6da9ajhxToIpKCFeaPGGP+OMAlPqC43/dFgceUUgqI/R2iA1m1rIQDbV28ss0dMw6hrHIR4NfAFmPMnYNc9gzwxcBql9MAvzFmXxjrVErFuOr6VqshGsM7RIOdX1pAQU4aj67d7XQpAITSmTgT+AJQLSIbAo/dBJQAGGP+C1gDXATUAh3ANWGvVCkV06p9fmYWZJOZGvsNUVtKkoerlhRz3yu11Ld0UDQ209F6hvxkjTFvADLENQb4SriKUkrFF7sheu7sAqdLCTs70B9/dw/f/MQcR2vRnaJKqYjb39bJwUPdlBfGz3SLrWhsJufN9vL4u3scX5Ouga6UirjjO0TznC0kQlYtm0JDexcvbWlwtA4NdKVUxFXH0Q7RgXxkjpeJY9J57J06R+vQQFdKRVy1z8+sghwyUpOcLiUikgPN0de2N7KnucOxOjTQlVIRZYyhuj5+dogO5qolxQjw+3edG6VroCulImqfv5Omw91xtaFoIJPzMvjInAL+sK7eseaoBrpSKqKO7RCN8xE6WDtHG9u7+OtmZ8530UBXSkVUdb2fJI/EbUO0v/PmFDA5N51HHWqOaqArpSLKaohmk54Snw3R/pI8wlVLSnh9+0HqmqLfHNVAV0pFzLEjc+N8/ry/q5YUk+QRHnOgOaqBrpSKmL3+TpoPdyfE/LltYm4655cW8MS6PXT3RLc5qoGulIqYYztEE2iEDrBqaQkHD3XzYpSboxroSqmIqfa1kuQRyhKgIdrfObO9FOZl8Og70T1WVwNdKRUx1b62hGmI9pfkEVYsKebN2iZ2HTwctffVQFdKRYS1Q7SVigSaP+/vsw40RzXQlVIR4Ws9QkvH0YSbP7dNGJPOx8oKeHJdfdSaoxroSqmIqPHF95G5oVi1bApNh7t5ftP+qLyfBrpSKiKq6v0ke4TSiTlOl+KYs2fmUzQ2g0fXRmfaRQNdKRUR1T4/syfkJFxDtD+PR1i5tIS3djSxo/FQ5N8v4u+glEo4ibhDdDBXLi4i2SNRufmFBrpSKuzqW47Q2nGU+Qm6wqW/gpx0Pj53Ak+ur6erpzei76WBrpQKO/vI3AodoQPWsbotHUf5S01km6Ma6EqpsKv2WQ3ROQncEO3vzBn5lIzLjHhzVANdKRV2NT4/cyYmdkO0P7s5unZnM7UNkWuODhnoIvKgiDSISM0gz58nIn4R2RD4c3P4y1RKxQpjDFX12hANdsWpkW+OhjJCfwi4YIhrXjfGLAz8uWX0ZSmlYlV9yxH8R44yXwP9Q7w5aXxy3kSeqqyn82hkmqNDBrox5jWgOSLvPgK1De184ddraTrU5XQpSqkBVAWOzE3UM1xOZtWyEloj2BwN1xz66SKyUUSeE5F5g10kIqtFZJ2IrGtsbBzRGzW0dfHOzmY+998a6kq5UbXPT0qSNkQHcvr08cybPIaDEcqucAR6JTDFGLMAuBd4erALjTH3G2MWG2MWe73eEb3ZGTPzefDqJexqOsyqB9ZG7INRSo2M3RBNS9aGaDCPR/jTV8/iurOnR+b1R/sCxpg2Y8yhwNdrgBQRyR91ZSdx5sx8HvzSEnY3H2bVA29rqCvlErpDdGgej0TutUf7AiIyUUQk8PXSwGs2jfZ1h2KP1OuaOzTUlXKJPc1WQ7S8MM/pUhJSKMsWHwPeAuaISL2IXCsi14vI9YFLrgBqRGQjcA+wwhhjIlfycWfMyOc3Vy9lT/MRVt7/No3tGupKOanK1wok3j1E3SJ5qAuMMSuHeP4+4L6wVTRMp88Yz2+uWcI1v3mXVQ+8zaP/eBrenDSnylEqodkN0dkTs50uJSHFxU7R06ZboV7fcoSVD7xNQ3un0yUplZBqfH5KJ47RhqhD4iLQwQr1h65Zwt5Wa/pFQ12p6LLuIerXDUUOiptAB1g2fTwPXbOUff5OK9TbNNSVipa65g7aOnt0Q5GD4irQAZZOG3cs1Fc8oKGuVLTYO0S1IeqcuAt0sEL94X9YygF/Jyvuf5sDGupKRVyNz09qkofZE3SHqFPiMtABlkwNhHqbNf2ioa5UZFX7/JROyiE1OW5jxfXi+pNf3C/UV2ijVKmIsXeIakPUWXEd6GCF+m+vXYqv9Qg/f/59p8tRKi7tbuqgvbNHbznnsLgPdIBTp4xj1dISnqysp66pw+lylIo7VYF7iOoI3VkJEegAXz5vBske4b5XtjtdilJxRxui7pAwgT5hTDqrlpXwVKWP3U2HnS5HqbhSXe+nTBuijkuoT//L5wZG6S/XOl2KUnGjr89Qow1RV0ioQC8Yk87nlk3hj+/52HVQR+lKhcPu5g7au3SHqBskVKADXH/udJI9wr06SlcqLKrqWwEXNUTf+k9Yc4PTVTgi4QK9YEw6nz9tCk9v0FG6UuFQ4/OTmuyihmj1E7DhMYjObRlcJeECHeCfzp1OSpJwz8u64kWp0ar2+SmbNIaUJBfESV8fNG6D7nbw1ztdTdS54J9A9BXkpPP5ZVN4+j0fO3WUrtSIWQ3RNsoLxzhdisW/B44G/p1u3OpsLQ5IyEAH+KdzZ5Ca7OHel3SUrtRI7Wo6zKGuHirccg/R/iHesMW5OhySsIHuzUnjC4G59B2Nh5wuR6mYVO22HaJ2iKeN0RF6ojk2StcVL0qNSHW9n7RkD7MmuOQeoo3bIGcSTD5FAz3R5Gen8cXTp/J/G3x8oKN0pYatyk0NUYDGLeCdA95SK9wTbKWLS/4pOGf1OdNJS07SuXSlhqmvz7B5b5t77lBkr3DxlkFBKXQfspqkCSThA90apU/hmY17qW3QUbpSodoZaIiWu2WHqL8OjnZYYe4tsx5rSKxpl4QPdLBG6ekpSdyr69KVClm12+4haoe3PUIHawomgQwZ6CLyoIg0iEjNIM+LiNwjIrUiUiUii8JfZmSND8ylW6P0dqfLUSomVPsCDdECtzREA+HtnQMZYyF7oo7QB/AQcMFJnr8QmBX4sxr41ejLir7V50wnIyWJe17SFS9KhaK63s/cyWNIdktDtGEr5EyGjDzr+4JSHaEHM8a8BjSf5JLlwG+N5W0gT0QmhavAaBmXlcqXzpjKn6r2sv2AjtKVOpm+PsOmvX73TLeAtUzRO+f4995SaHzfapYmiHD8p7UQ6N9Krg88dgIRWS0i60RkXWNjYxjeOrz+8ezpZKYkcbeueFHqpHYcPMzh7l73BHpfHxx8HwrKjj/mLbWOAUiglS5R/X8lY8z9xpjFxpjFXq83mm8dEnuU/mz1Pt7XUbpSg6r2tQK4Z4VL625rhYu39Phjdrgn0AajcAS6Dyju931R4LGYpKN0pYZWXd9GeoqHmV63NEQDoR08QoeEOtMlHIH+DPDFwGqX0wC/MWZfGF7XEWOzUrn6zKmsqd7Htv06SldqINW+VuZOclNDtN8KF1tGnnUMgI7QjxORx4C3gDkiUi8i14rI9SJyfeCSNcAOoBZ4APjniFUbJdedNZ2s1GTu0VG6Uifo7TNs2ttGRVGe06Uc17gVxhRCetAUkLc0oUboyUNdYIxZOcTzBvhK2CpygbFZqVx9xlTue6WWr+1vZ85El9yJRSkX2HnwEB3dve45YRECK1xKT3y8oAzWP2Q1TT0u+b+JCIr/v8MRuu7saWSnJXPrmi2YBDvgR6mT2bjHZTtE+/qs5YkDBbp3jtUs9ddFvy4HaKAPIi8zlW99Yjavvd/IE+sS71ZWSg3mvT0tZKclM9MtO0Rbd0HPkePb/ftLsDNdNNBP4ounT2XZtHH88M+b2dt6xOlylHKFyt2tLCzOI8kjTpdi6X+GSzC7SZogO0Y10E/C4xF+esUCevoMN/6xWqdeVMI71NXD1v1tLCrJc7qU4xoHWOFiy8izjgPQEboCKBmfyXcuKuW19xt5/N3E2XGm1ECq9rTSZ+CUKWOdLuW4hq0wpgjSB7lRdQKd6aKBHoLPL5vCadPH8aNnt+DTqReVwCrrWgBYVOyiQG/cMvD8uc1bljBnumigh8CeeukzhhufqtKpF5WwKutameHNIjczxelSLH29cHD7wCtcbN45VtO0dXf06nKIBnqIisdl8p2Lynh9+0Eee0enXlTiMcbwXl0Lp7ppuqVlF/R0njzQE+hMFw30Yfjc0hLOmDGeW5/dTH1Lh9PlKBVVOw8epqXjKItKXBToA53hEsxulibAjlEN9GHweIQ7Lq8A4N906kUlmMq6VgAWuWmEPtAZLsHSc61jAXSEroIVj8vkpovLeLO2iUfWJsbuM6XAaojmpCe754RFsEI6txjShjieI0HOdNFAH4FVS0s4a2Y+t63Zwp5mnXpRiaFydwsLi/PwuGVDEVhLFk82f24rKLNugNHXG/maHKSBPgIiwu2Xl+MR4dtPVtHXp1MvKr61dx5l24F2d82f9/VaIX2y6Rabd47VPI3zlS4a6CNUNDaT715cxls7mnhkbXz/kii1cY8fY1w2f96yC3q7Tt4QtSXImS4a6KOwYkkxZ8/K58fPbaWuSadeVPyyNxQtLM5ztpD+jjVEQwn0xDjTRQN9FESsVS9JItzw5EadelFxq7KuhdkTssnNcMmGIjj5GS7B0sdYxwPoCF2dzOS8DL53SRlrdzbzu7d16kXFn74+w3t1re6aPwcrnHNLIC3EVTcJcKaLBnoYfHZxMefO9nL7c1vZ3XTY6XKUCqsdBw/jP+KyDUVgLVk82Rkuwbyl1jEBcbzSRQM9DOxVL8lJwg266kXFmcrdgQO5puQ5W0h/vT1Dn+ESrKDMWunSsitiZTlNAz1MJuVm8O+XzOWdnc08/NYup8tRKmwq61oYk57M9HwXbSiyV7gMJ9Dta+N4x6gGehhdeWoRH5nj5Y6/bGXnQZ16UfGhsq6FU0rGumtDkT0XPqwpl/g/00UDPYxEhB9/poKUJA/f1lUvKg60dR5le8Mh982f26tV8kNY4WJLy7GOCdARugrVxNx0/uPSeby7q4Xf/H2X0+UoNSob6loDG4rynC7lwxq3QN4wVrjYvKVxvXRRAz0CLl9UyEdLC/jJX7ayo/GQ0+UoNWKVdS2IuGxDEQTOcAlhQ1GwgtK4PtMlpEAXkQtEZJuI1IrIjQM8f7WINIrIhsCf68JfauwQEW77TDlpyR5ueLKKXp16UTGqsq6VORNyyEl30Yai3h5o2j68+XObt8xqpjbvDH9dLjBkoItIEvBL4EJgLrBSROYOcOnjxpiFgT//HeY6Y86EMel8/7J5rN/dwoNvxOcvj4pv1oYiqyHqKi07obd7eCtcbHG+0iWUEfpSoNYYs8MY0w38Hlge2bLiw6dPKeRjZRP42Qvb+ECnXlSMqW08RHtnD4tK8pwu5cOOneEykkCP7zNdQgn0QqD/TTTrA48Fu1xEqkTkSREpHuiFRGS1iKwTkXWNjY0jKDe2iAi3fXo+6SlJ3PDERp16UTHl+IYil43Q7dF1KGe4BEvLto4LiNPGaLiaon8CphpjKoAXgYcHusgYc78xZrExZrHX6w3TW7tbwZh0fnDZPCrrWvn1GzucLkepkFXWtZCXmcL0/CynS/mwhi2QNwVSR1hXQWlCT7n4gP4j7qLAY8cYY5qMMV2Bb/8bODU85cWH5Qsn84m5E/jZC+9T29DudDlKhaSyrpVTivMQcdGGIgic4TKCFS42b2ClS29P+GpyiVAC/V1glohME5FUYAXwTP8LRGRSv28vA+JzgmqERIQffXo+malJfOsJXfWi3M/fcZRaN24o6j06/DNcghWUWU3VlvhbrDBkoBtjeoCvAs9jBfUfjDGbROQWEbkscNnXRGSTiGwEvgZcHamCY1VBjjX1smFPKw+8rlMvyt3e22PNn5/qtvnz5p3Qd3R0gR7HRwAkh3KRMWYNsCbosZv7ff0d4DvhLS3+XLZgMs9V7+fOF97no6UFzJowxJ3KlXJIZV0rHoEFbttQNJIzXILZxwU0bht9PS6jO0WjSET44afmk5WWxLee2EhPb5/TJSk1oPfqWpgzcQxZaSGN+aKnYSsgwzvDJVhatnVsQBwuXdRAjzJvTho//NR8Ntb7uV+nXpQL9R67Q1Ge06WcqHELjJ0CqZmjex1vWVwuXdRAd8AlFZO5qHwid724nW37ddWLcpftDe0c6upxX0MURn6GS7CCUuv4gDhb6aKB7pBbls8nOz2Zbz2xkaM69aJcpHJ3K+DCDUW9R6GpdnTz5zZvYKVLc3z9X7IGukPys9P44fL5VPv8/L9XP3C6HKWOqaxrYVxWKlPHj3JaI9yaPhj9ChdbnB4BoIHuoIsrJnFxxSTufmk7W/e3OV2OUkDgDkVu3VAEYQ70+Frp4rIWduK55bJ57KrdyqsPfo/fzbmaPgn9H0lGSjLXnzedgpz0CFaoEklrRzc7Gg9z+aIip0s5UaO9wmX26F8rNcs6PmA0a9G7DsE798OiL0JW/uhrCgMNdIeNz0zm0bH/RW7TRv5rUxcPJl0Z8s82H+6mtvEQD1+zxH2jKRWT3qtrBXBpQ3QLjJ06+hUutoKy0Z3p8sL3YP1voH4drHgEXPDvoAa60/5+L7lNG8FbyvVNT3H9tf8CE+eH9KO/fWsXN//fJh5/dw8rlpZEuFCVCNbvbiHJIywoznW6lBON9gyXYN5SqH3JarYmDfMGHh+8YoW5txS2PQvVT0DFZ8NX2wjpHLqTGrbCK7dB6SVwzXOQMRaevt76BQvB55dN4fTp4/nRs1vwtR6JcLEqEVTWtVA6MYfMVJeN9Xq6rRUu4Zg/txWUWU3W4a506WyDZ/4Fxs+Cf3wZipbCmhugfX/4ahshDXSn9PbA01+25vIu+QVkjoNL74L91fD6z0N6CY9H+MkVFfQZw41PVWGMHvqlRq63z7BxT6s7p1uaP4C+nvCP0GH48+gvfA/afPCpX1n//n7qP6GnE/70DXD430ENdKf8/R7YWwkX/wyyC6zHSi+G8s/Caz+FfVUhvUzxuExuuqiM17cf5LF39gz9A0oNYtv+dg5397JoSp7TpZxoNDe1GEz+bECGN49e+xJUPgxn/AsULwm8ziw4/9/h/eeg6vHw1TcCGuhOaNgCf/sxlF0G8z7z4ecuvAMyx1uj957ukF7uc8tKOHPmeG59djN7mjsiULBKBJV1gTsUuXGE3rAVxBOeFS621EzrGIFQA73Tb0215M+B82768HOnfRmKT4Pnvg1t+8JX4zBpoEebPdWSlgMX33liZzxzHFxyFxyogdd/FtJLigh3XF4BwI1/1KkXNTKVdS2Mz0qlZJzLNhRB4AyXqZCSEd7XHc6ZLs9/F9r3WVMtKUFLhT1JsPyX1iDsT193bOpFAz3a3rwL9r4HF/8csge5DV/pRVCxwppL37shpJctGpvJdy+ey5u1TTyyti5s5arE8V5dK4umjHXnEthwneESrKDUarYOtRBh+1/hvd/BmV+HokFuyJY/Ez56M2x/HjY8Gv5aQ6CBHk0HNsHfboe5n4J5nz75tRfeDpn58PQ/hzz1snJpMWfPyue2NVt06kUNS/PhbnYePOzO6ZaebqspGo4zXIJ5Aytdmk5y/MaRVmuqxVsK5w1x24dl10PJ6fCX70Db3rCWGgoN9GjpPWpNtaTnWqPzoWSMhUvvhoZN8NpPQnoLEeH2yyvwiPDtJ6vo01vdqRBV7rbnz/OcLWQgTbXWCpdIjdDh5Ge6PP9dOHTAWs2SnHby1/N4rKmX3m545mtRn3rRQI+WN+6CfRvhkjtD3yY85wJYsApev9OapglBYV4G37u4jLd2NPHI2t0jr1cllMq6FpI9QkVRntOlnMgO23CucLGNnwXI4PPo7z8PG/4HzvoGFA4y1XLCa86Aj30fal+E9/4nTIWGRgM9GvbXwKt3wPzLYe7y4f3sBT+2ljX+75ehpyukH7lqSTHnzPZy25qt1DXp1IsaWmVdC2WTxpCRmuR0KSdq3Bb+FS621Eyr2TrQSpcjLVaDs2AunPtvw3vdpathypnw/E3grw9LqaGIvUDvaIY3fgFdMXJjCHuqJSMPLvzp8H8+Iw8uu9capbx6R0g/IiLc/plykj3CDU9u1KkXdVI9vX1s3ON353QLBM5wmXbiypJwGexMl7/cBIcaQptqCWZPvfT1RHXqJfYC/f3n4a/fh7vK4bWfWdtw3ez1O2F/lbUbNGv8yF5j1sdh4eetaRvf+pB+ZHJeBv9+yVzW7mzmd2/r1Isa3Nb97Rw52uu+G1rYwn2GSzBvYKVL/8UH256DjY/C2f8Kk08Z2euOmwYf+wF88BJU/jY8tQ4h9gJ94Uq4LnB+wss/DAT7T90Z7PurrYZm+ZVQdunoXuuTt0LORGvVy9HOkH7kysVFnDfHy+3PbWV30+HRvb+KW++5eUNRT5e1AiWcZ7gEKyizRtLNgZUuR1qsbfwT5sM53x7day+5DqaebTVWWyO/kzv2Ah2sdaCf+4N1ME7JafDyj6xgf9VFwd7THZhqGQcXhrZK5aQy8uCye6zRyqu3h/Qj1tRLBclJwg1P6KoXNbDKula8OWkUjQ3zpp1waKoF0xv5ETocP9PluRuh42BgqiV1dK/t8cDy+8D0WUsfIzz1EpuBbis8FVY9Dqv/Zq39fMUO9p9Y23Sd9PrPrRH6pXdZuz/DYebH4JQvwJt3W2cwh2Bibjo3XzKXd3Y189Dfd4WnDhVX1u9uYVGJC+9QBMdDNhIrXGz5s6yma+NW2LoGqn4PZ38TJi0Iz+uPnQof/wHseAXWPxSe1xxESIEuIheIyDYRqRWRGwd4Pk1EHg88v1ZEpoa90pOZfAqs+r0V7FPOgFdutYL9b3c4E+z7qqxt+xVXWQduhdMnb4WcydboP8SplytOLeL80gJ+8vxWdh7UqRd13MFDXdQ1d7hzugWOr3AZPyty75GSYYVu3Vvw52/AhHI4+1vhfY/F18K0c6yTGlsi19MaMtBFJAn4JXAhMBdYKSJzgy67FmgxxswEfgGEthwj3CafAisfg9WvwpSz4G+3BYL9dmu3VzTYUy2Z4+GC0KZGhiU915p6Ofi+9fcXAhHhx58pJzXJww1PbKRXp15UwLENRa5tiG6BcdMjt8LF5i2Dna9BR1N4plqCeTxw2X3W1xGcegnlFPulQK0xZgeAiPweWA5s7nfNcuD7ga+fBO4TETFOnRI1eSGsfNTayPPqT6yTDf9+H+QWRv69j3ZAax2s/H34plqCzfwonHo1/P1ea9VPCCYAb+QcZf++Tup+6HHD3bKUC8zoM7yYapjx52xX3ELtBC27rKnGSCsI3HnonG/DpIrIvMfYKfDxW+DZf4V1D8KSa8P+FqEEeiHQvz1bDywb7BpjTI+I+IHxwMH+F4nIamA1QElJFG6ZNmmBda+/fVXw7gPRm3457Ssw58LIvscnfgSeFDjcEPKP5AANaYdo6QztjkgqMeRlpOLxZjldxsC8pREJvhMsWAl9vdYyxUha/A+w+82I3VRahhpEi8gVwAXGmOsC338BWGaM+Wq/a2oC19QHvv8gcM3BgV4TYPHixWbdutAae0oppSwist4Ys3ig50JpivqA4n7fFwUeG/AaEUkGcoGm4ZeqlFJqpEIJ9HeBWSIyTURSgRXAM0HXPAN8KfD1FcDLjs2fK6VUghpyDj0wJ/5V4HkgCXjQGLNJRG4B1hljngF+DfxORGqBZqzQV0opFUWhNEUxxqwB1gQ9dnO/rzuBK8NbmlJKqeGI7Z2iSimljtFAV0qpOKGBrpRScUIDXSml4sSQG4si9sYijcBIT6nJJ2gXagLTz8Kin4NFPwdLPH8OU4wx3oGecCzQR0NE1g22UyrR6Gdh0c/Bop+DJVE/B51yUUqpOKGBrpRScSJWA/1+pwtwEf0sLPo5WPRzsCTk5xCTc+hKKaVOFKsjdKWUUkE00JVSKk7EXKAPdcPqRCEiu0SkWkQ2iEhC3SlERB4UkYbAjVXsx8aJyIsisj3wV5feJDN8Bvkcvi8ivsDvxQYRucjJGqNBRIpF5BUR2Swim0Tk64HHE+53IqYCPcQbVieSjxhjFibgetuHgAuCHrsReMkYMwt4KfB9vHuIEz8HgF8Efi8WBk5KjXc9wDeNMXOB04CvBHIh4X4nYirQ6XfDamNMN2DfsFolEGPMa1jn7ve3HHg48PXDwKeiWZMTBvkcEo4xZp8xpjLwdTuwBes+xwn3OxFrgT7QDasLHarFaQZ4QUTWB26+negmGGP2Bb7eD0xwshiHfVVEqgJTMnE/zdCfiEwFTgHWkoC/E7EW6Oq4s4wxi7Cmn74iIuc4XZBbBG5/mKjrcX8FzAAWAvuAnztaTRSJSDbwFPANY0xb/+cS5Xci1gI9lBtWJwRjjC/w1wbgf7GmoxLZARGZBBD4a4PD9TjCGHPAGNNrjOkDHiBBfi9EJAUrzB8xxvwx8HDC/U7EWqCHcsPquCciWSKSY38NfAKoOflPxb3+Nyr/EvB/DtbiGDvAAj5NAvxeiIhg3dd4izHmzn5PJdzvRMztFA0sw7qL4zesvtXZiqJPRKZjjcrBui/so4n0OYjIY8B5WEekHgD+A3ga+ANQgnUs82eNMXHdMBzkczgPa7rFALuAf+o3jxyXROQs4HWgGugLPHwT1jx6Yv1OxFqgK6WUGlisTbkopZQahAa6UkrFCQ10pZSKExroSikVJzTQlVIqTmigK6VUnNBAV0qpOPH/AfLaSaKbUPklAAAAAElFTkSuQmCC\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "## call the optimization function\n", + "model, buy, soc, feedin_cost_minimizing = optimze_battery_operation(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh)\n", + "\n", + "# read results\n", + "buy_results = []\n", + "soc_results = []\n", + "feedin_cost_minimizing_results = []\n", + "\n", + "for i in range(0,24):\n", + " buy_results.append(buy[i].value())\n", + " soc_results.append(soc[i].value())\n", + " feedin_cost_minimizing_results.append(feedin_cost_minimizing[i].value())\n", + "\n", + "# print results calculated with time series\n", + "c_total_optimal = get_total_costs(buy_results, c_euro_kWh)\n", + "print(f\"The total electricity costs are {round(c_total_optimal,2)} €\")\n", + "\n", + "# print results from objective value (validation)\n", + "c_total_optimal = model.objective.value()\n", + "print(f\"The total electricity costs are {round(c_total_optimal,2)} €\")\n", + "\n", + "# plots\n", + "plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp)\n", + "\n", + "# !!! insert plot for Battery SOC\n", + "plt.plot(soc_results)\n", + "\n", + "# !!! insert plot for electricity bought\n", + "plt.plot(buy_results)\n", + "\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "312a055f", + "metadata": {}, + "source": [ + "The SOC of the battery starts and ends at 50% of the maximum capacity, as this is specified by the constraints. Initially, the battery discharges as no PV power is generated. It is sufficient to charge the battery in the last hours of the day, as the size of the battery is comparatively small. It can be seen that the grid power is drawn in the time steps when the grid power is most favorable." + ] + }, + { + "cell_type": "markdown", + "id": "8c3cc635", + "metadata": {}, + "source": [ + "# Task 2 e)\n", + "Change the battery optimization function (1 Variable, 1 Objective, 1 Constraint) below so that the maximium (single peak value, not sum of all values!) feed in from the pv plant to the grid gets minimized. How much was the maximum feed in without battery operation, with cost minimizing battery operation and with feed-in minimizing battery operation? Plot the resulting feed-in time series." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "4e8c2c60", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The maximum feed-in without battery operation is 9.1 kW.\n", + "The maximum feed-in with cost minimizing battery operation is 7.2 kW.\n", + "The maximum feed-in with feed-in minimizing battery operation is 6.2 kW.\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAEGCAYAAABvtY4XAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAABU8klEQVR4nO3dd1iUx9rA4d/s0rsIgg1RsdNERYoae9QYS2JMMc2cJCfRmF40vZzkM8f0dlLV9GKMJbYYExWNvSBYwYIiIgIK0lnY+f54AUHKLspS574uLuGtj8vyMMw784yQUqIoiqI0P7qGDkBRFEWxDJXgFUVRmimV4BVFUZopleAVRVGaKZXgFUVRmimrhg6gPA8PD+nr69vQYSiKojQZu3fvTpNSela1r1EleF9fX3bt2tXQYSiKojQZQoiT1e1TXTSKoijNlErwiqIozZRK8IqiKM1Uo+qDV5SqGAwGTp8+TX5+fkOHoigNxs7Ojg4dOmBtbW32OSrBK43e6dOncXZ2xtfXFyFEQ4ejKPVOSkl6ejqnT5+mc+fOZp+numiURi8/P5/WrVur5K60WEIIWrduXeu/YlWCV5oEldyVlu5KfgZUgleUKySlJD27gHxDcUOHoihVUgleUUx47LHHeO+998q+vvbaa7n33nu5kGsgKSOP+2c+wguvzeXX35Yyd+5cAJYuXcrBgwfLzhk6dGidTeJ74403qt3n6+tLQEAAwcHBBAQEsGzZslpdLyMjg08++aRO4lQankrwimJCZGQkW7ZsAcBoNJKWlsaBAwc4dzEfe2s9B6N30jOoP91Dh3LrfbPIKyyulODrUk0JHmD9+vVER0fz66+/8vDDD9fqeleS4KWUGI3GWp2j1A+V4BXFhIiICLZu3QrAgQMH8Pf3x87BkbT087jZCY7GHWHyqEGsX76IOU88xqJV61i6bDlPPvkUwcHBHDt2DIBFixYRGhpK9+7d2bRpE6A9QJ4+fToBAQH07duX9evXA7Bw4UIeeuihshjGjx/Phg0bmD17Nnl5eQQHBzNt2rQa47548SKtWrUq+3rSpEn069ePPn368PnnnwNUut7s2bM5duwYwcHBPPXUUwDMmzePAQMGEBgYyEsvvQRAQkICPXr04M4778Tf35/XXnuNRx99tOxeX3zxBY899tjVvOxKHVDDJJUm5ZXfD3DwzMU6vWbvdi68dH2fave3a9cOKysrTp06xZYtWxgYFoZD3AkOx+yGDC8CAgJwsLfD1cEaN0drrh1+DUNHjWHwiGu58cYptHGxBaCoqIgdO3awatUqXnnlFdatW8fHH3+MEILY2FgOHz7M6NGjiYuLqzaWuXPn8tFHHxEdHV3tMcOGDUNKyfHjx/nll1/Kts+fPx93d3fy8vIYMGAAN954Y6XrJSQksH///rKv165dS3x8PDt27EBKyYQJE4iKisLHx4f4+Hi+/vprwsLCyM7OJigoiHnz5mFtbc2CBQv47LPPzP8mKBahEryimCEiIoItW7awZcsW7nngIaRja47E7OJCkjuRkZFlx+mEwMvFDld7a9zsrckpLOLoOQP5hmLGjp8AQL9+/UhISABg8+bNzJo1C4CePXvSqVOnGhO8OdavX4+HhwfHjh1jxIgRDB06FCcnJz744AOWLFkCQGJiIvHx8bRu3brGa61du5a1a9fSt29fALKzs4mPj8fHx4dOnToRFhYGgJOTE8OHD2fFihX06tULg8FAQEDAVf0/lKunErzSpNTU0rak0n742NhYWnf0I8zdi9++/gwXFxemT59e6XghBK4ONvT0diE9pwCjhNRcI8dTs9EXSYqKimq8n5WVVYV+7SuZxdu1a1e8vLw4ePAgubm5rFu3jq1bt+Lg4MDQoUPNuqaUkjlz5vDvf/+7wvaEhAQcHR0rbLv33nt544036NmzZ5WviVL/VB+8opghIiKCFStW4OzqhhFBj05tycjIYOvWrURERFQ63tnZmaysLPQ6QRtnO+xt9Hg42ZJvMJKQnoNRSgAGDx7M999/D0BcXBynTp2iR48e+Pr6Eh0djdFoJDExkR07dpRd29raGoPBYDLmc+fOceLECTp16kRmZiatWrXCwcGBw4cPs23btiqvVxp3qWuvvZb58+eTnZ0NQFJSEufOnavyfgMHDiQxMZEffviBW2+91WR8iuWpFryimCEgIIC0tDRGTbgRR1srnOysCQgIIDs7Gw8Pj0rH33LLLdx333188MEH/PrrrwiglaMNPb2dyc+6QLFRUmw0MmPGDB588EECAgKwsrJi4cKF2NraEhkZSefOnenduze9evUiJCSk7Nr3338/gYGBhISElP1yKG/YsGHo9XoMBgNz587Fy8uLMWPG8Omnn9KrVy969OhR1rVS1fUiIyPx9/dn7NixzJs3j0OHDhEeHg5oXTHfffcder2+ytdp6tSpREdHV3i4qzQcIUtaEo1B//79pVrwQ7ncoUOH6NWrV0OHQWpWAcmZeXTxdMLJ9srbRnmFRcSfy8bb1Y42znZ1GGHDGz9+PI899hgjRoxo6FCapap+FoQQu6WU/as6XnXRKIoZio2S1KwCnGytriq5A9jbaNdIyyrEaGw8DayrkZGRQffu3bG3t1fJvRFRXTSKYob0nAKKjEa8XBzq5HptnG05npbDhdxCWjvZ1sk1G5Kbm9tVj/5R6p5qwSuKCcVGSVpWAc521jheZeu9lKOtFQ42VqRmF9CYukmV5kUleEUxIT27gCKjxMul7lraQgg8nW0pLDKSmWd6RIyiXAmV4BWlBsVGI6nZBbjYWeNgU7c9mi52Vtha6UnNUq14xTJUgleUGqRlF1Jcx633UqWt+DxDMdkFNU98UpQroRK8olSjqNhIWnYB7//neT775KOy7aXlgks98cQTvPPOOyxfvrzW5YLdHKyx1us4l1UAaJOdxo0bR7du3QgJCWHq1KmkpKTUKm5TFSGFENx+++2X/p9FRXh6ejJ+/HiACv+P6pw5c4YpU6bUKq4XX3yRdevWXfH+2lBlk0tIKRvNR79+/aSiXO7gwYMNct/kjDy5L/GC/P7Hn+VNN90kpZSyuLhYhoSEyLCwsLLjwsLC5NatWyuce9ddd8lFixaVfX3NNdfInTt3Vnmfcxfz5b7ECzItI0v6+fnJ5cuXl+1bv369jI2NrVXcJ06ckH369Kl2v6OjowwKCpK5ublSSilXrVolg4KC5HXXXVer+zRmnTp1kqmpqVJKKQ8fPix9fHxMnuPo6Fj2uanXsCpGo1EWFxfXLtBaqupnAdglq8mpqgWvKFUoKjaSnl2Aq701Q4cMqlQu2NnZmQsXLlBQUMChQ4cICQkpK/G7ZcsWli9fzlNPmS4XDODuaINeJ/hq4beEh4dz/fXXl+0bOnQo/v7+1ZYVPnDgAKGhoQQHBxMYGEh8fHyVJX8vN27cOFauXAnAjz/+WKG0QPlSxXfffTcPP/wwERERdOnShV9//RXQatH4+/uXHT9p0iRGjRqFr68vH330Ee+88w59+/YlLCyM8+fPl13r119/ZdeuXQQHB5e1rkuXoivdD1oL/KWXXiIkJISAgAAOHz4MQGpqKqNGjaJPnz7ce++9dOrUibS0tBq/ly25bLIaB680Latnw9nYur2mdwCMrdglkZZdQLGUeLnYYWftWKFccHh4OElJSWzduhVXV1cCAgKwsbEpOzciIoIJEyYwfvz4Ct0YVZULBtDrBK2dbIndv5+g4L5VhlhdWeFPP/2URx55hGnTplFYWEhxcTFz586tUPK3Krfccguvvvoq48ePJyYmhnvuuafCL53ykpOT2bx5M4cPH2bChAlVds3s37+fvXv3kp+fj5+fH2+++SZ79+7lscce45tvvqmQ9Pr3718W21NPPcWYMWOqvK+Hhwd79uzhk08+4a233uLLL7/klVdeYfjw4cyZM4c1a9bw1VdfVft/VGWTVYJXlEq0vvdC3OxtsLPWaq6ULxf8+OOPk5SUxJYtW3B1da1QLrgmN9xwA1CxXHApD0cbhKDah63VlRUODw/n9ddf5/Tp09xwww1069bNrFgCAwNJSEjgxx9/ZNy4cTUeO2nSJHQ6Hb179672ecCwYcNwdnbG2dkZV1fXsr9CAgICiImJqfKcn3/+mT179rB27doq95d/vX777TdAex1KSx6PGTOmxpo3qmyySvBKUzO25od/daF08lGbciNnypcL9vf3p2PHjrz99tvVlguuiq2tdj29Xl+pXLCVXkdQgD8bNm6ksMiIjZV5vae33XYbAwcOZOXKlYwbN47PPvuMLl26mHXuhAkTePLJJ9mwYQPp6ekm4waqHc5Z/hidTlf2tU6nq7I08v79+3n55ZeJioqqtnBZTa9XbbTksskW7YMXQjwmhDgghNgvhPhRCNG8KispzY6h2Eh6diFuDpda73CpXLC7uzt6vR53d3ezygXXxr1338G+XTv4afHSsm1RUVHs37+/2rLCx48fp0uXLjz88MNMnDiRmJgYs+99zz338NJLL9V7CzMjI4Nbb72Vb775Bk9Pz1qdGxkZWdbdsnbtWi5cuGDynJZcNtliCV4I0R54GOgvpfQH9MAtlrqfotQFbdKRViumvNJyweXL7AYEBODq6lptueB58+bRt2/fsoesprg6O/H1T4v5/H+f0K1bN3r37s0nn3yCp6cnM2bMwGg0EhAQwM0331xWVviXX37B39+f4OBg9u/fz5133knr1q3LSv5W95AVoEOHDmYtyl3Xli1bxsmTJ7nvvvvKHraa66WXXmLt2rX4+/uzaNEivL29cXZ2rvLYYcOGERwczLBhwyqUTS4qKqJXr17Mnj27yrLJ06ZNq/Qajh49mttuu43w8HACAgKYMmVKjb9Ep06dSmRkZIOXTbZYueCSBL8NCAIuAkuBD6SUVXe4ocoFK1Wrr3LBhmIjR85m4WpvTUf3uikqVlv5hmLiUrLwcrHDy0X9wXu5goIC9Ho9VlZWbN26lQcffLDGh8kNxVJlk2tbLthiffBSyiQhxFvAKSAPWFtVchdC3A/cD+Dj42OpcBTFpLLWuwVmrZrLzlqPi501adkFeDjZoteJBoulMTp16hRTp07FaDRiY2PDF1980dAhVZCRkUFoaChBQUGNomyyxRK8EKIVMBHoDGQAi4QQt0spvyt/nJTyc+Bz0FrwlopHUWpSWGQkPaeQVo7W2FpV/dCvvng623Ix1cCFnEI8nJt+KeG61K1bN/bu3dvQYVSrsZVNtuRD1pHACSllqpTSAPwGVH4apSiNwLmL2kiKy/veG4KjrRWOtlopYaOFulCVlsGSCf4UECaEcBDaVLURwCEL3k9RrkieoVhbeMPRBpsGbr2X8nS2xVBsJCNXlRJWrpzFEryUcjvwK7AHiC251+eWup+iXKmzmfnodKJRtN5LOdtaYWetSgkrV8ei4+CllC9JKXtKKf2llHdIKQsseT9Fqa2sfANZ+QbaONthpW88pZmE0H7hFBQVczFflRJWrkzjeUcrSj2TUpKcmY+NlY7WTjbVHvfYY4/x3nvvlX1dl+WCy0tISMDe3r5sbPjQiFAwFl1VK758UbDL1bY874YNGxBC8OWXX5Zti46ORgjBW2+9ZfY1zSlHfLlx48aRkZFxxfvNVf57EBQUREREBEeOHDF5zg8//FD2dXR0NKtWrbrqWOqCSvBKi3Uh10C+oRhvFzt0ovrhiKVlCgCMRiNpaWkcOHCgbP+WLVvKCozNnj0bqJzgzdW1a1eio6PLPtq7O5NbWEROYXGtr2XKq6++ysiRI2t1jr+/f4XCXT/++CNBQUG1umb518lcq1atws3N7Yr310bp92Dfvn3cddddFerEV6UuEvzVlGKoiUrwSotkNEpSLubjYGOFq711jcdGRERYtFxwTVo52LB903qGDIokJCSEm266qWy6/O7du7nmmmvo168f1157LcnJyWXbg4KCCAoK4uOPP6722uaU571cp06dyM/PJyUlBSkla9asYezYsbW65uXliB988EHCwsLo0qULGzZs4J577qFXr17cfffdZdf19fUlLS2NTz/9tOwvnM6dOzNs2LAK+xMSEujVqxf33Xcfffr0YfTo0eTl5QGwc+dOAgMDy0oAV/eXTXnlSw0nJCQwePBgQkJCCAkJKfulP3v2bDZt2kRwcDBvvvkmL774Ij///DPBwcH8/PPP5OTkcM899xAaGkrfvn3LFh9ZuHAhEyZMYPjw4YwYMYI777yTpUuXlt172rRpZi1UUhNVbExpUt7c8SaHz1edfGqjsNiIociInbWePh69eCb0mWqPbdeunUXLBZdXWoMctL8cXnnlFeZ/9DaffP8bQb7efPDuW7zzzjvMmTOHWbNmsWzZMjw9Pfn555957rnnmD9/PtOnT+ejjz5iyJAhNZYquFxV5XmrMmXKFBYtWkTfvn0JCQmpUGjsSq554cIFtm7dyvLly5kwYQL//PMPX375JQMGDCA6OrpCKYMHHniABx54AIPBwPDhw3n88ccrXS8+Pp4ff/yRL774gqlTp7J48WJuv/12pk+fzhdffEF4eHiNf0GUfg+ysrLIzc1l+/btALRp04Y///wTOzs74uPjufXWW9m1axdz587lrbfeYsWKFQB4eXmxa9cuPvpIWwXs2WefZfjw4cyfP79sIlTpXzl79uwhJiYGd3d3Nm7cyLvvvsukSZPIzMxky5YtfP3119XGaQ6V4JUWR0owFBnR64TZM0UtXS64VGn3QKkVK1YQf+Qwd08eg04noLiI8PBwjhw5wv79+xk1ahQAxcXFtG3bloyMDDIyMhgyZAgAd9xxB6tXr651fKXleasydepUbr75Zg4fPsytt95a1pK90mtef/31CCEICAjAy8urrPhZnz59SEhIqLJWzSOPPMLw4cMrLI5SqnPnzmXnlL7WGRkZZGVlER4eDmhVOEsT8uXKfw9+/vln7r//ftasWYPBYOChhx4iOjoavV5v9oSmtWvXsnz58rLnFPn5+Zw6dQqAUaNG4e7uDsA111zDjBkzSE1NZfHixdx4441YWV1dilYJXmlSamppmyvpQi7ncwx093LC1tq8ce+WLhdcHSklo0aN4r3PFpByMZ8OrRxwd7QhNjaWPn36lHUdlarpQeP06dPZu3cv7dq1q7KP2Nz4vL29sba25s8//+T999+vMcGbc83ypYUvLztc1TkLFy7k5MmTZS3k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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Import of necessary packages\n", + "from pulp import LpProblem, LpVariable, lpSum, LpMinimize\n", + "\n", + "# Create a new model\n", + "def optimze_battery_operation_PV(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh):\n", + " model = LpProblem(\"charging_optimization\", LpMinimize)\n", + "\n", + " # Decision Variables\n", + " buy = LpVariable.dicts(\"buy\", range(24), lowBound=0) # The amount of electricity (in kW) bought from the grid at time t\n", + " soc = LpVariable.dicts(\"soc\", range(25), lowBound=0, upBound=E_bat_kWh) # The State of Charge (in kWh) of the battery at time t\n", + " discharge = LpVariable.dicts(\"discharge\", range(24), lowBound=0, upBound=P_bat_max_discharge_kW) # Discharge rate (in kW) at time t\n", + " charge = LpVariable.dicts(\"charge\", range(24), lowBound=0, upBound=P_bat_max_charge_kW) # Charge rate (in kW) at time t\n", + " feedin = LpVariable.dicts(\"feedin\", range(24), lowBound=0) # The amount of electricity (in kW) sold to the grid at time t\n", + " consumed_pv = LpVariable.dicts(\"consumed_pv\", range(24), lowBound=0) # The amount of electricity (in kW) consumed directly from PV at time t\n", + "\n", + " # !!! insert new decision variable\n", + " max_pv_feed_in = LpVariable(\"max_pv_feed_in\", lowBound=0)\n", + "\n", + " # !!! insert new objective function\n", + " model += max_pv_feed_in, \"Minimize_Max_Feedin\" #lpSum(0)\n", + "\n", + " # Constraints\n", + " model += soc[0] == E_bat_kWh/2\n", + " model += soc[23] == E_bat_kWh/2\n", + "\n", + " # Energy balance for consumed electricity\n", + " for t in range(24):\n", + " model += el_demand_kW[t] == consumed_pv[t] + buy[t] + discharge[t]\n", + "\n", + " # Energy balance for generated electricity\n", + " for t in range(24):\n", + " model += pv_kWp * pv_pu[t] == charge[t] + feedin[t] + consumed_pv[t]\n", + "\n", + " # State of Charge\n", + " for t in range(23):\n", + " model += soc[t+1] == soc[t] + charge[t] - discharge[t]\n", + "\n", + " # !!! insert new constraint\n", + " for t in range(23):\n", + " model += max_pv_feed_in >= feedin[t]\n", + "\n", + " # Solve the optimization problem\n", + " model.solve()\n", + "\n", + " return model, buy, soc, feedin\n", + "\n", + "# call optimization function\n", + "model, buy, soc, feedin = optimze_battery_operation_PV(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh)\n", + "\n", + "# read results\n", + "feedin_results = []\n", + "\n", + "for i in range(0,24):\n", + " feedin_results.append(feedin[i].value())\n", + "\n", + "# max feed-in without battery:\n", + "max_feedin_1 = max(pv_kWp * np.array(pv_pu) + np.array(el_demand_kW))\n", + "\n", + "print(f\"The maximum feed-in without battery operation is {max_feedin_1} kW.\")\n", + "\n", + "# max feed-in with cost minimizing battery operation:\n", + "max_feedin_2 = 0 # !!! <-- insert calculation\n", + "max_feedin_2 = max(feedin_cost_minimizing_results)\n", + "print(f\"The maximum feed-in with cost minimizing battery operation is {max_feedin_2} kW.\")\n", + "\n", + "# max feed-in with feed-in minimizing battery operation:\n", + "max_feedin_3 = max(feedin_results)#0 # !!! <-- insert calculation\n", + "print(f\"The maximum feed-in with feed-in minimizing battery operation is {max_feedin_3} kW.\")\n", + "\n", + "# !!! insert plots\n", + "plt.plot(range(24), pv_kWp * np.array(pv_pu) + np.array(el_demand_kW), label='Without Battery')\n", + "plt.plot(range(24), feedin_cost_minimizing_results, label='With Cost Minimizing Battery')\n", + "plt.plot(range(24), feedin_results, label='With Feed-in Minimizing Battery')\n", + "\n", + "plt.xlabel('Time (hours)')\n", + "plt.ylabel('Feed-in (kW)')\n", + "plt.legend()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01ca0a8e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97f4c29d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Excercise_1/Quickstart.ipynb b/Excercise_1/Quickstart.ipynb deleted file mode 100644 index bd022ba..0000000 --- a/Excercise_1/Quickstart.ipynb +++ /dev/null @@ -1,293 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "# Jupyter Example Profile Quickstart\n", - "\n", - "Welcome to JupyterLab!\n", - "\n", - "* Execute a single cell: <span class=\"fa-play fa\"></span>\n", - "* Execute all cells: Menu: Run <span class=\"fa-chevron-right fa\"></span> Run All Cells\n", - "* To reboot kernel: <span class=\"fa-refresh fa\"></span>\n", - "\n", - "Find more in the reference (menu: Help <span class=\"fa-chevron-right fa\"></span> Jupyter Reference)." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "jp-MarkdownHeadingCollapsed": true - }, - "source": [ - "## Markdown\n", - "\n", - "ou can specify the cell type which is either _Code_ or _Markdown_. \n", - "\n", - "### Lists\n", - "\n", - "* Like\n", - "* this\n", - " 1. We can even nest them like\n", - " 2. this!\n", - "* Isn't that wonderfull?\n", - " \n", - "### Images \n", - "\n", - "\n", - "\n", - "### LaTeX equations\n", - "\n", - "$$\\mathrm{e}^{\\mathrm{j} x} = \\cos(x)+\\mathrm{j}\\sin(x)$$\n", - "\n", - "### Code\n", - "\n", - "``` python\n", - "print(\"Hello world!\")\n", - "```\n", - "\n", - "### Further reading\n", - "Read more in the reference (menu: Help <span class=\"fa-chevron-right fa\"></span> Markdown Reference)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Python" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## numpy\n", - "\n", - "Execute the cell below to see the contents of variable `a`" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hello world!\n" - ] - } - ], - "source": [ - "print(\"Hello world!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Plots with matplotlib\n", - "\n", - "Nice matplotlib [tutorial](https://matplotlib.org/tutorials/introductory/usage.html#sphx-glr-tutorials-introductory-usage-py)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 0, 1, -5])" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy as np\n", - "\n", - "a = np.array([0, 1, -5])\n", - "a" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib widget\n", - "import matplotlib.pyplot as plt\n", - "import rwth_nb.plots.mpl_decorations as rwth_plots\n", - "\n", - "fs = 44100;\n", - "(t, deltat) = np.linspace(-10, 10, 20*fs, retstep=True) # t axis in seconds\n", - "\n", - "fig,ax = plt.subplots(); ax.grid();\n", - "ax.plot(t, np.sin(2*np.pi*t), 'rwth:blue')\n", - "ax.set_xlabel(r'$t$'); ax.set_ylabel(r'$s(t) = \\sin(2 \\pi t)$'); " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Interactive Widgets\n", - "\n", - "Jupyter Widgets. You can find a detailled widget list [here](https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html).\n", - "This requires to install [Jupyter Matplotlib](https://github.com/matplotlib/jupyter-matplotlib) which is called with the `%matplotlib widget` magic.\n", - "\n", - "Uses Python [decorators](https://docs.python.org/3/glossary.html#term-decorator)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import ipywidgets as widgets\n", - "\n", - "# Create figure\n", - "fig0, ax0 = plt.subplots(); \n", - "\n", - "# Create update function and decorate them with widgets\n", - "@widgets.interact(F = widgets.FloatSlider(min=0.1, max=10, step=0.1, value=0, description='$F$:'))\n", - "def update_plot(F): \n", - " # Generate signal with given F\n", - " s = np.sin(2*np.pi*F*t)\n", - " \n", - " # Plot\n", - " if not ax0.lines: # decorate axes with labels etc. (which is only needed once)\n", - " ax0.plot(t, s, 'rwth:blue'); \n", - " ax0.set_xlabel(r'$t$'); ax.set_ylabel(r'$s(t)=\\sin(2 \\pi F t)$')\n", - " else: # update only lines and leave everything else as is (gives huge speed-up)\n", - " ax0.lines[0].set_ydata(s)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Audio" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import Audio, Latex\n", - "\n", - "def audio_play(s, fs, txt=\"\", autoplay=False):\n", - " if txt: display(Latex(txt))\n", - " display(Audio(s, rate=fs, autoplay=autoplay))\n", - "\n", - "# Create sin\n", - "s = np.sin(2*np.pi*440*t)\n", - "\n", - "# Play back\n", - "audio_play(s, fs, r'$s(t)$')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## RWTH Colors" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# adapted from https://matplotlib.org/2.0.0/examples/color/named_colors.html\n", - "\n", - "colors = rwth_plots.colors.rwth_colors;\n", - "ncols = 5; nrows = len(colors.keys()) // ncols + 1;\n", - " \n", - "fig, ax = plt.subplots()\n", - "X, Y = fig.get_dpi() * fig.get_size_inches() # Get height and width\n", - "w = X / ncols; h = Y / (nrows + 1)\n", - "\n", - "for i, name in enumerate(colors.keys()):\n", - " col = i % ncols\n", - " row = i // ncols\n", - " y = Y - (row * h) - h\n", - " \n", - " xi_line = w * (col + 0.05); xf_line = w * (col + 0.25); xi_text = w * (col + 0.3)\n", - " ax.text(xi_text, y, name, fontsize=10, horizontalalignment='left', verticalalignment='center')\n", - " ax.hlines(y + h * 0.1, xi_line, xf_line, color=colors[name], linewidth=(h * 0.6))\n", - " \n", - "ax.set_xlim(0, X); ax.set_ylim(0, Y); ax.set_axis_off();\n", - "fig.subplots_adjust(left=0, right=1, top=1, bottom=0, hspace=0, wspace=0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Magic\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%svg\n", - "\n", - "<svg width='300px' height='300px'>\n", - "\n", - "<title>Small SVG example</title>\n", - "\n", - "<circle cx='120' cy='150' r='60' style='fill: gold;'>\n", - " <animate attributeName='r' from='2' to='80' begin='0' \n", - " dur='3' repeatCount='indefinite' /></circle>\n", - "\n", - "<polyline points='120 30, 25 150, 290 150' \n", - " stroke-width='4' stroke='brown' style='fill: none;' />\n", - "\n", - "<polygon points='210 100, 210 200, 270 150' \n", - " style='fill: lawngreen;' /> \n", - " \n", - "<text x='60' y='250' fill='blue'>Hello, World!</text>\n", - "\n", - "</svg>" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.9.18" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/Excercise_1/main.ipynb b/Excercise_1/main.ipynb deleted file mode 100644 index daab14b..0000000 --- a/Excercise_1/main.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# main" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.9.18" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/Excercise_2/2023_12_01_DEV_UE2_A2_v1.0_students.ipynb b/Excercise_2/2023_12_01_DEV_UE2_A2_v1.0_students.ipynb new file mode 100644 index 0000000..790a5d6 --- /dev/null +++ b/Excercise_2/2023_12_01_DEV_UE2_A2_v1.0_students.ipynb @@ -0,0 +1,539 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# DEV Exercise 2" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "This Jupyter notebook contains tasks that are calculated for you on the blackboard during the exercise session. To practice using python and to see the advantage of programming when dealing with data, you will reprogram parts of it in this Jupyter notebook. If you have not yet installed the packages required for this exercise, run the following cell to install them." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "!pip install pandas\n", + "!pip install numpy\n", + "!pip install scipy\n", + "!pip install openpyxl" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "Now run the following cell to import the most important libraries. You can run a cell either by clicking `Run` on the toolbar or by pressing `CTRL+RETURN`." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true, + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-01-03T15:01:38.782849Z", + "start_time": "2024-01-03T15:01:34.983511400Z" + } + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import numpy as np\n", + "from scipy.optimize import curve_fit" + ] + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "### Predefine functions\n", + "It is good programming practice to define functions at the beginning that you want to use again and again in the course of the code. You can find instructions with examples for defining functions under the following [link](https://www.w3schools.com/python/python_functions.asp). In the course of this exercise, you will need to complete functions at this point. " + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [], + "source": [ + "def round_up(x, decimals: int):\n", + " \"\"\"\n", + " Returns the numerical value given in \"value\", rounded up to the given number of decimal places given in \"decimals\". This function is particularly relevant when dealing with measurement uncertainties, as these must always be rounded up.\n", + "\n", + " :param x: value to be rounded\n", + " :param decimals: number of decimals\n", + " :return: rounded up value\n", + " \"\"\"\n", + " value = np.ceil(pow(10, decimals)*x) / pow(10, decimals)\n", + "\n", + " return value\n", + "\n", + "def uri(U,I):\n", + " \"\"\"\n", + " Returns the value for the resistance following Ohm's law U=R*I\n", + " :param U: voltage value\n", + " :param I: current value\n", + " :return: resistance value\n", + " \"\"\"\n", + " # Complete the code\n", + " return\n", + "\n", + "def calc_sig_R(U, I, sig_I):\n", + " \"\"\"\n", + " Returns the value of the uncertainty of the resistance according to Ohm's law and Gaussian error propagation\n", + " :param U: voltage value\n", + " :param I: current value\n", + " :param sig_I: uncertainty of the resistance\n", + " :return: \n", + " \"\"\"\n", + " # Complete the code\n", + " return \n", + "\n", + "def weighted_mean(x, sig_x):\n", + " \"\"\"\n", + " Returns the weighted mean of variables x and their uncertainties sig_x\n", + " :param x: array with x values\n", + " :param sig_x: array with uncertainty of respective x value\n", + " :return: weighted mean\n", + " \"\"\"\n", + " # Complete the code\n", + "\n", + " return \n", + "\n", + "def sig_weighted_mean(sig_x):\n", + " \"\"\"\n", + " Returns the uncertainty of the weighted mean of variables x and their uncertainties sig_x\n", + " :param sig_x: array with uncertainty of respective x value\n", + " :return: uncertainty of weighted mean\n", + " \"\"\"\n", + " # Complete the code\n", + "\n", + " return \n", + "\n", + "\n", + "def ml_estimator(x, y, sig_y):\n", + " \"\"\"\n", + " Returns the parameter m that is determined by using the maximum likelihood method.\n", + " :param x:\n", + " :param y:\n", + " :param sigma:\n", + " :return: m\n", + " \"\"\"\n", + " # Complete the code\n", + "\n", + " return \n", + "\n", + "def chi2_formula(x, y, sig_y, R):\n", + " \"\"\"\n", + " Formula to calculate the Chi^2 value in the case of the relationship y = x/R\n", + " :param x: x values\n", + " :param y: y values\n", + " :param sig_y: uncertainty of y values\n", + " :param m: slope\n", + " :return: \n", + " \"\"\"\n", + " # Complete the code\n", + "\n", + " return \n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-01-03T15:01:44.000874400Z", + "start_time": "2024-01-03T15:01:43.987393800Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2a\n", + "First, the measurement data must be read in from the Excel spreadsheet. The table contains the measured voltages and currents, each with their uncertainties. Use the [pd.read_excel](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html) function to do this.\n" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 6, + "outputs": [ + { + "ename": "ImportError", + "evalue": "Missing optional dependency 'openpyxl'. Use pip or conda to install openpyxl.", + "output_type": "error", + "traceback": [ + "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[1;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)", + "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\compat\\_optional.py:142\u001B[0m, in \u001B[0;36mimport_optional_dependency\u001B[1;34m(name, extra, errors, min_version)\u001B[0m\n\u001B[0;32m 141\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 142\u001B[0m module \u001B[38;5;241m=\u001B[39m \u001B[43mimportlib\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mimport_module\u001B[49m\u001B[43m(\u001B[49m\u001B[43mname\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 143\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m:\n", + "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python38\\lib\\importlib\\__init__.py:127\u001B[0m, in \u001B[0;36mimport_module\u001B[1;34m(name, package)\u001B[0m\n\u001B[0;32m 126\u001B[0m level \u001B[38;5;241m+\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m1\u001B[39m\n\u001B[1;32m--> 127\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43m_bootstrap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_gcd_import\u001B[49m\u001B[43m(\u001B[49m\u001B[43mname\u001B[49m\u001B[43m[\u001B[49m\u001B[43mlevel\u001B[49m\u001B[43m:\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpackage\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mlevel\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[1;32m<frozen importlib._bootstrap>:1014\u001B[0m, in \u001B[0;36m_gcd_import\u001B[1;34m(name, package, level)\u001B[0m\n", + "File \u001B[1;32m<frozen importlib._bootstrap>:991\u001B[0m, in \u001B[0;36m_find_and_load\u001B[1;34m(name, import_)\u001B[0m\n", + "File \u001B[1;32m<frozen importlib._bootstrap>:973\u001B[0m, in \u001B[0;36m_find_and_load_unlocked\u001B[1;34m(name, import_)\u001B[0m\n", + "\u001B[1;31mModuleNotFoundError\u001B[0m: No module named 'openpyxl'", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001B[1;31mImportError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[1;32mIn[6], line 3\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[38;5;66;03m### First, the data needs to be loaded from the given xlsx-file. Note that all datatypes shall be set to float.\u001B[39;00m\n\u001B[1;32m----> 3\u001B[0m data \u001B[38;5;241m=\u001B[39m \u001B[43mpd\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mread_excel\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mmeasurement_data.xlsx\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mindex_col\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdtype\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mfloat\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[0;32m 5\u001B[0m \u001B[38;5;66;03m### Define arrays with the corresponding voltage and current values for later use.\u001B[39;00m\n\u001B[0;32m 6\u001B[0m U \u001B[38;5;241m=\u001B[39m data\u001B[38;5;241m.\u001B[39mloc[:, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mvoltage\u001B[39m\u001B[38;5;124m\"\u001B[39m]\n", + "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\io\\excel\\_base.py:478\u001B[0m, in \u001B[0;36mread_excel\u001B[1;34m(io, sheet_name, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, parse_dates, date_parser, date_format, thousands, decimal, comment, skipfooter, storage_options, dtype_backend)\u001B[0m\n\u001B[0;32m 476\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(io, ExcelFile):\n\u001B[0;32m 477\u001B[0m should_close \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mTrue\u001B[39;00m\n\u001B[1;32m--> 478\u001B[0m io \u001B[38;5;241m=\u001B[39m \u001B[43mExcelFile\u001B[49m\u001B[43m(\u001B[49m\u001B[43mio\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mstorage_options\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mengine\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mengine\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 479\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m engine \u001B[38;5;129;01mand\u001B[39;00m engine \u001B[38;5;241m!=\u001B[39m io\u001B[38;5;241m.\u001B[39mengine:\n\u001B[0;32m 480\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[0;32m 481\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mEngine should not be specified when passing \u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 482\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124man ExcelFile - ExcelFile already has the engine set\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 483\u001B[0m )\n", + "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\io\\excel\\_base.py:1513\u001B[0m, in \u001B[0;36mExcelFile.__init__\u001B[1;34m(self, path_or_buffer, engine, storage_options)\u001B[0m\n\u001B[0;32m 1510\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mengine \u001B[38;5;241m=\u001B[39m engine\n\u001B[0;32m 1511\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mstorage_options \u001B[38;5;241m=\u001B[39m storage_options\n\u001B[1;32m-> 1513\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_reader \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_engines\u001B[49m\u001B[43m[\u001B[49m\u001B[43mengine\u001B[49m\u001B[43m]\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_io\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mstorage_options\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\io\\excel\\_openpyxl.py:548\u001B[0m, in \u001B[0;36mOpenpyxlReader.__init__\u001B[1;34m(self, filepath_or_buffer, storage_options)\u001B[0m\n\u001B[0;32m 533\u001B[0m \u001B[38;5;129m@doc\u001B[39m(storage_options\u001B[38;5;241m=\u001B[39m_shared_docs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mstorage_options\u001B[39m\u001B[38;5;124m\"\u001B[39m])\n\u001B[0;32m 534\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__init__\u001B[39m(\n\u001B[0;32m 535\u001B[0m \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m 536\u001B[0m filepath_or_buffer: FilePath \u001B[38;5;241m|\u001B[39m ReadBuffer[\u001B[38;5;28mbytes\u001B[39m],\n\u001B[0;32m 537\u001B[0m storage_options: StorageOptions \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[0;32m 538\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[0;32m 539\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m 540\u001B[0m \u001B[38;5;124;03m Reader using openpyxl engine.\u001B[39;00m\n\u001B[0;32m 541\u001B[0m \n\u001B[1;32m (...)\u001B[0m\n\u001B[0;32m 546\u001B[0m \u001B[38;5;124;03m {storage_options}\u001B[39;00m\n\u001B[0;32m 547\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n\u001B[1;32m--> 548\u001B[0m \u001B[43mimport_optional_dependency\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mopenpyxl\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[0;32m 549\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(filepath_or_buffer, storage_options\u001B[38;5;241m=\u001B[39mstorage_options)\n", + "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\compat\\_optional.py:145\u001B[0m, in \u001B[0;36mimport_optional_dependency\u001B[1;34m(name, extra, errors, min_version)\u001B[0m\n\u001B[0;32m 143\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m:\n\u001B[0;32m 144\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m errors \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mraise\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[1;32m--> 145\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m(msg)\n\u001B[0;32m 146\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m 148\u001B[0m \u001B[38;5;66;03m# Handle submodules: if we have submodule, grab parent module from sys.modules\u001B[39;00m\n", + "\u001B[1;31mImportError\u001B[0m: Missing optional dependency 'openpyxl'. Use pip or conda to install openpyxl." + ] + } + ], + "source": [ + "### First, the data needs to be loaded from the given xlsx-file as a pandas dataframe called 'data'. Note that all datatypes shall be set to float.\n", + "\n", + "data = ...\n", + "\n", + "### Define arrays with the corresponding voltage and current values for later use.\n", + "U = \n", + "sig_U = \n", + "I = \n", + "sig_I = " + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-01-03T15:02:26.578566600Z", + "start_time": "2024-01-03T15:02:26.440889500Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2b\n", + "After the data has been read in, the resistance and its uncertainty are to be determined for the value pairs. \n", + "Add the corresponding code to the functions in the cell above to calculate the resistance with the function <code> def uri(U,I) </code> and the uncertainty with the function def <code> def calc_sig_R(U, I, sig_I) </code>. Why does the function <code> def calc_sig_R(U, I, sig_I) </code> not have the uncertainty of the voltage as an input variable? Note that the propagated uncertainty must always be rounded up." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "First add the code here to calculate the resistance with the function<code> def uri(U,I) </code> and add them to your pandas dataframe. Round the values to a suitable number of decimal places using the function [round](https://docs.python.org/3/library/functions.html#round)" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 32, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " voltage voltage_sig current current_sig resistance resistance_sig\n", + "0 10.0 0.0 1.55 0.08 6.45 0.34\n", + "1 15.0 0.0 2.19 0.11 6.85 0.35\n", + "2 20.0 0.0 3.00 0.15 6.67 0.34\n", + "3 25.0 0.0 3.97 0.20 6.30 0.32\n", + "4 30.0 0.0 6.18 1.55 4.85 1.22\n" + ] + } + ], + "source": [ + "# Calculate and round the resistance\n", + "data.loc[:, \"resistance\"] = " + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Now calculate the uncertainty, round it and add it to the dataframe. Then print the dataframe to check your results." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "# Calculate resistance uncertainty\n", + "# Remember that uncertainties shall always be rounded up!\n", + "\n", + "### Print resulting table in one line\n", + "pd.set_option(\"expand_frame_repr\", False)\n", + "print(data)" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2e\n", + "Now we have several pairs of measured values with different measurement uncertainties. In order to combine the information including the measurement uncertainties, we need to determine a suitable estimated value for the resistance. Calculate an estimation value for the resistance first using the arithmetic mean by using the function [np.mean](https://numpy.org/doc/stable/reference/generated/numpy.mean.html) and secondly using the expression for the weighted mean. The weighted mean is defined by the following formula, which you must add under the function <code> def weighted_mean(x, sig_x) </code>:\n", + "\n", + "\n", + "\n", + "$\\left<x\\right>=\\frac{\\sum_{i=1}^N x_i / \\sigma_{i,abs}^2}{\\sum_{i=1}^N 1 / \\sigma_{i,abs}^2}$\n", + "\n", + "\n", + "Also calculate the uncertainty of the calculated mean values, in each case using the function [np.std](https://numpy.org/doc/stable/reference/generated/numpy.std.html) for the arithmetic mean and the function <code> def sig_weighted_mean(sig_x) </code> for the weighted mean. In advance, add the following formula to the function <code> def sig_weighted_mean(sig_x) </code> using [np.sqrt](https://numpy.org/doc/stable/reference/generated/numpy.sqrt.html):\n", + "\n", + "$\\sigma_{\\left<x\\right>}=\\frac{1}{\\sqrt{\\sum_{i=1}^N 1 / \\sigma_{i,abs}^2}}$\n", + "\n", + "Remember to round the values to a meaningful number of decimal places using [round](https://docs.python.org/3/library/functions.html#round) and <code> def round_up(x, decimals) </code>. \n", + "Compare your results and explain where the differences come from! \n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 33, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " weighted arithmetic\n", + "mean 6.52 6.22\n", + "uncertainty 0.17 0.72\n" + ] + } + ], + "source": [ + "# Extract the needed data from our dataframe\n", + "\n", + "n = data.shape[0] # number of measurements\n", + "R = \n", + "sig_R = \n", + "\n", + "# Calculate the arithmetic mean and its uncertainty and round your results\n", + "ar_mean = \n", + "sig_ar_mean = \n", + "\n", + "# Calculate the weighted mean and its uncertainty and round your results\n", + "w_mean = \n", + "sig_w_mean =\n", + "\n", + "# Create and print a Dataframe with results\n", + "results_2e = pd.DataFrame(np.array([[ w_mean, ar_mean], [ sig_w_mean, sig_ar_mean ]]), columns=[\"Weighted\", \"Arithmetic\"], index=[\"Mean\", \"Uncertainty\"])\n", + "print(results_2e)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2f\n", + "\n", + "In the lecture and the first part of this exercise session, we learned about the maximum likelihood method on the one hand and solved the analytical solution of the problem here using the ML method on the other.\n", + "According to Ohm's law, $I = U/R = m*U$ with $m=1/R$. This results in a linear relationship between the current and the voltage. Using the ML method, we have calculated that the following equation applies for m:\n", + "\n", + "$m = \\frac{\\sum_{i=1}^N \\frac{x_i \\cdot y_i}{\\sigma_i^2}}{\\sum_{i=1}^N \\frac{ x_i^2}{\\sigma_i^2}}$\n", + "\n", + "In this case, $x = U$, $y = I$ and $\\sigma_y = \\sigma_I$. Add the function <code> def ml_estimator(x, y, sig_y) </code> to the function cell and determine both the value for the ML estimator $m$ and then the value for the resistance. Round the value for the resistance to a meaningful number of decimal places and compare the value for the resistance with the previous ones. \n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 34, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m = 0.152\n", + "\n", + " weighted arithmetic ML-method\n", + "0 6.52 6.22 6.58\n" + ] + } + ], + "source": [ + "# Extract needed data from dataframe\n", + "x = \n", + "y = \n", + "sig_y = \n", + "\n", + "# Calculate best estimate for the parameter m\n", + "m = \n", + "R_ml = \n", + "print(\"m = \" + str(m) + \", R = \"+str(R_ml))\n", + "\n", + "# Create and print a Dataframe with results\n", + "results_2f = pd.DataFrame(np.array([[w_mean, ar_mean, R_ml]]), columns=[\"weighted\", \"arithmetic\", \"ML-method\"])\n", + "print(results_2f)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2g\n", + "\n", + "In practice, the majority of functional relationships can no longer be determined analytically using the ML method. For these cases, the Python package [Scipy](https://scipy.org/) can be used. The [scipy.optimize.curve_fit](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html) function can be used to estimate the parameters of previously defined functional relationships for a specific data set. In the scipy documentation you will find all relevant information and steps for the implementation. \n", + "Use the function to fit a linear relationship to the measurement data according to task 2f). Compare the result for the resistance with the previous ones. \n", + "\n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "# First, the linear relationship needs to be defined as a function\n", + "\n", + " \n", + "\n", + "# Use curve_fit to solve the problem and print the parameter m with its uncertainty\n", + "\n", + "\n", + "# Calculate the resistance and its uncertainty (Hint: Think about Gaussian Error Propagation!)\n", + "\n", + "\n", + "\n", + "# Create and print a Dataframe with results\n", + "results_2g = pd.DataFrame(np.array([[w_mean, ar_mean, R_ml, R_sc]]), columns=[\"weighted\", \"arithmetic\", \"ML-method\", \"Scipy Curve-Fit\"])\n", + "print(results_2g)\n" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2h\n", + "\n", + "The $\\Chi^2$ test, which is defined as follows, is suitable for determining the quality of the fit:\n", + "\n", + "$\\chi^2 = \\sum_{i=1}^N \\frac{(y_i - f(x_i, m))^2}{\\sigma_i^2}$\n", + "\n", + "Where $x=U$, $y=I$, $\\sigma_i = \\sigma_y_i$ and $f(x_i,m) = U_i/R$. Complete the function <code> def chi2_formula(x, y, sig_y, R) </code> and calculate the $\\Chi^2/n_{d.o.f.}$ for the results from tasks 2f and 2g. Explain what the numerical values for $\\Chi^2/n_{d.o.f.}$ mean.\n", + "\n" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 35, + "outputs": [], + "source": [ + "# Determine n_dof\n", + "\n", + "n = # Hint: The number of degrees of freedom is the number of measurements minus the number of parameters which were fitted \n", + "\n", + "# Calculate the Chi^2 and Chi^2/ndof for task 2f\n", + "\n", + "\n", + "# Calculate the Chi^2 and Chi^2/ndof for task 2g\n", + "\n", + "\n", + "# Print the resulting Chi^2/ndof\n", + "print(\"Chi^2/ndof (ML-Method) = \" + str(round(chi2_ml_n), 4))\n", + "print(\"Chi^2/ndof (Scipy) = \" + str(round(chi2_sc_n), 4))" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Excercise_2/main.ipynb b/Excercise_2/main.ipynb deleted file mode 100644 index d8e9a62..0000000 --- a/Excercise_2/main.ipynb +++ /dev/null @@ -1,69 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# main" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'pandas'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m\n", - "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'pandas'" - ] - } - ], - "source": [ - "import pandas" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.9.18" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/Excercise_2/measurement_data.xlsx b/Excercise_2/measurement_data.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e94f54b2f1a9ca80fe7a64efee4abe9889a89d2f GIT binary patch literal 8737 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 Hc@Pf($E^_< literal 0 HcmV?d00001 diff --git a/Excercise_3/340px-English-slf(1).png b/Excercise_3/340px-English-slf(1).png new file mode 100644 index 0000000000000000000000000000000000000000..6431723cc3736d149d90d33dd835198b795b3c41 GIT binary patch literal 10402 zcmeAS@N?(olHy`uVBq!ia0y~yU<_ekU=-wFVqjocoqEESfq{Xuz$3Dlfq}sTjNMLV z+kphj3LMj6su{`_Zmniu(6IM(aSW-r_4aONfOL2h`-i;J*Dg*>vI-M+=+8d<vG$02 z&T;XwH%HvnCND`!PdD;hnw7QPY<KWVudDBBJg(-IZJs%$yevB_J<DibSFw*;S(5ce z#UE_V9~loy@GvD8dfa(o_xlFF?dhtXs6v@X4L|<d?bz@o<H6p4ulK&IyW9Vyavnp& zPWL7)28SPv3=i2ETI3l7>L46-jzjOiZ{N1f&&TJ^-y{<$S$X;Sf7YLV+U26OqOjoz zXT6G$W#y+QA0HpL|Np0W`)%DlFUoe;|9u_*|KIoh;{U8|Z2r9e|L^_Yy?epR_g{Z4 zD=+{5c>SN_875WF&&f6^RLt97_IB3ox63l4B$%#TyLQi5kD)<c?C)LkhebOj+7@O; zX-(y_wfCI#`uckF*=N(w&r{`Cw0Cdp^2@rBn_3pFIQhP4_ubmsS{2W%tx?@ao2D_$ zsC^i|`l{0^$+p0iA&0tEJh_D1oflqEpI@Ui(Idxfw$s85QELws9C%q$_wlIs!hnpD zk}nSqHmi6pGGs`L{4sg*<jh%h|Nnls?AsinvpxU*wg?@gnLZN#y_a74`}=!;f4{tS z*_ot`9xC;g7c?|M;A7R^|DW{#A1b_ax0#7yhU~*|t*KL|PMxk78?`a1^<>Jc7cT^U z{W){yjPGo-K#|aZ00)7Viy0;}eI`E?H{fYDW0<k_p*qK*9JBW~H@p9+y0@qDka*PE zu+>-nrky-{*0q%RjLeKD%ncuy84mF?aM&{_{9z!5<6|!sdY~}ILgtx;-x>zbNkuzl z_@$Uz>@RNFwr$_fXR}wXTzTm7@nvfFpBC-?aEN>A)Tt}99exOR9e?cU?|*-5cK8`~ zu1hAd;o;_HW^G+eE%p~DsA%d~34H$eu<#z!jH?BQ_>q&#QP;&67cN{Fpiy%E^&xGW z^Zfk${XIQL_Do}Au<yvUxP9Kh$Jf_4Ha0dg^5(g@)~#Eu4nO>`e16@lj}>v1PpAI+ z^=s9tRT(C`YJY!om#-C>$~Qs5cK`L)Z(qNz{`>X1t(?EVfB%K6@p~#ZZrphB`RCTd ziOVnl{5=2vp977|v9YliGrqige^k|^A@a^=e;=O>I;+E0ryAY-@neU;%dOehmn~g- z_1d*lDVvthtLjR<xoelz=9@Ze&g=5<-pSj3`|Yu)xeS|4|8TWBMO05ujZ93<Yf?xt zl5`EUIX_wD<@ewH^7iX4W|-yNFt~a3cFs0_`#%OETsvddRZn}z+HlkG&GnZhERI*M zTya@^v8Si!;lsp*#?LF~J+^2|touCseo0BmlBG*|d3k;3eb(02uKs-1{C>sb-Yr|U zSeRdBIB<q{zt_@R8xjw%jov;@H#*I1c6D`iD|7YalUr(j7EMb%n^qhYbg7kF+{()8 zo!vwKNh*Cm8Ph&)n6J=r2n3uSzE<^~#t|>k>$do!hrp5I^S13>Y#s;ZAu=*bt|rVu zDguxcC#-9?7wR-IGrN_uZFl?=i@bz{hSbO_76*77{eO#PXJ<!8MJ)-^^qj=X%F5!% z!qm9fy+3Y8!Na@d_d~U&t|)0>dGk}U?d7XiRs|0Z?5X@bYxe9`@#^a8SiR{76LwTj zJ-5H++Xa(ruUI@<=GhByurM)px-1INsIi;>A<5IzGcD~|e%<HUyARu&nO(bh@!{91 zzjgMX_zhkkULUk_ikIr~!igR(OM~v#o~ifW{=R7Etl6`f8yz%6oQxUH{7SU<y&M@C z+0G}stMql4tLxFXx3?cZb}VVyne*rCzg`WGuY4-HH_rZR0Rux?<avLABfq}B4%M1^ zFhN68^X2>Z%QI&wbSzo2r1tkWO_8o@F89TOD)I`Bht>yZTw5EhUX!~qLd~6J=gyrg z@)}xXzY)l(mz&%~58M&tYj<~Zv*;7nc9^u}V#b^*;Zt{b>n&vD<mJsJc!E}nSPPtq z`}*~3{{Fw)jwW@^tnYL&GBEh?dH(;J&(F?s{Ev58d@*>rUvFQZUgV}Fd-mK(Fi0?O zx~U<;6&ezfb9-BF;tYwz1uxg{`=uqplXT<%|0`Kv`|JNao;GdTty{N}kN1g+h~(Vc zW2vsr&dfNYw_;v@rSi|1-MjzP_5T#*I{N45XLmQZyt})uUb<vtX0|QiVAH8nUQgr| zCLWgWbU8Q2viRjC)#igACeQz~WYHoe5w5G(ue&b}Y>`(uc=-ILH<SJCex6Y7=ZIgv zWJ%85U7<<`r#dy<e6{b=>Y$Y}eC`GkQ#@44-`)B7<8lAthX#}QC;WK${bx<x{{36F zOi|!ief8DXDt31Ez;cF8`#1hxUYnxUmX?-U&DE3O@mhLm$`p|+vJQ{F{}FM`y|-tk z%E@KR)b`)spMQVflP4)4nfCb#9TO)`bWlhzntAA9L2>cs`|sWFGOGOBaQ|tMtW}A} z`s>+Sqvk!I>ZK~Tjo(21(0KzM&q=?(zrUWfb%jxbrAS??)5Gt->%Z^5|MdCuVwvTa zUxuxTDEuB&voPSq!vcw3w_Z2pJwlx>zkdI2J;-!=Q*CW+&`J|yW8-6u?JiD%B2i2U zYHjgK6W2s;PAe!V$jRw>UfH!MV%prA@EvcTzh1xp-09QRuU0O<l4W{&Q~J3%J8OP! zx|(%&bGm<V@#j`<agL@N+w<c+Jx|(3zkB!2uHr+&oJi)@*4F54IgY`MKI?zaee(H6 za(`-S>eQ)I-`?9>{qoY%$+k9*0&(lhD=L0`y&lic)@*BQ%i_q=?6~{xzwY=yP0L<> z`}S?ywrziZf6u?M;o-BhvxDu!IGPe7r**eJ|G9DFMqzco1#=ndX3Vn}>Xfl8TC#cb z<phHlUw<VZ@B8~@x&7Qdx6BO<4{ll$qc{Czir(~Y1&-~vW%=4gxmukTeyFhd{OoM? z`@P>ax^C?(e*VPlZ{7b7A2u9+9H=3}EvD09`AOZgsG{P>r>Cbg)Eng0{v1rW@cL`s zogEj`HZNVatVqV(&dyHq-;yOuPV&X*P3Kl-eb^>HEwyr9erD#)eYL+IJV@~N_O7h7 z^qj=vc;oFi`~N@BFAT^?N^*L0QcK12UTqB{1Hbhjsa`c}>)reI-FsMIz%zN~%$XA> z8va}twtA|EihG|-qQtSJjbFZgefhO&X;9^p6N2ln?=E?HY2CVY@80E2KVAAg*x}jv z`Tza@fAN>=e=h&;p?twZfrPfU`6?%m%h%f&8*g5}Uf<Ss@18w>-dR^p^?Eu@H~QRM z>+NZ0XKmTCWwv?#ET3g-qqm2JhwDdgTeDz+!`iU<HkFq$O!DsT3VrcS{b=PZDTY5E zKuO)bU#`?bM#VF3SINqa8$Zs={udb;slVq#(}z-5S5`-XmoHyVUcY4d^8G&^b+5>7 zxG7%O>a?-uXVL!q=RenkhhKksdU~=Q6EB01?w_EQTQ+P6__1rjf(4s57uVFptiQha z7lTm!jrun?Ha0dgPEv7RDBvhi(V%}|4u`$(<;u!RP~~5*E7tv?bHbD<CFeP9W^A_T zd;R7O4+~S_DG8poHEVRPT+QLCH<7Zf{+5%Tp6=$>w&8(iRaKRz=gE6}tDm2^rB+~n z_^|oCio-c($KUXKO#1S(=H$tf@Av)IdzEF@8m~0*N6o&y)!(O0oA&L?7a7Z<l<)8E zhOG`&o4k-Mano~i37+b2Zv<zru{1GhIXP>y{vQ?3sI}K7O%mE0cm8utUS6J?TieA9 zm#+u!R?JJ6P<u8-*XP=twGYErhIEVRT2+2pa{Ted43pE-_5HoQo$oTL)cxRWirAJD znU?nK$B!L1bB?X7YhWpe-~Q#3P5s+jTjT%#x_*6qeEH58b^m!s1o#sCTJFF99>1$3 z^I#LJ-F*M$m+$T<WIq3veTMME=^iRUE2pGJ&Oe{N{kCS;A)#7^;zu*$D<+)}kFPZ~ zFbD__|Ni4~|7;(%D|bykRoEO-zT|SdbD6P`QN}E{*n`fz^$G$7R&(|Dd|(1KyJ9Mm z*nJj%zhD3V&d%bMD_166Kl$s|FFrY&8T04&?`mq7`sbli^zTn)uUqoQ2&P5`-^-es zniWspnRK}*_1k`nsI06!W4uztwf4h7_K6-WqOAO;e`JnNR5@vI=Kr7b|7ZB9^*uH+ zGMZQY&Qj;P`QD0o;&Rbao1f4Bxqp9%*3n)$PSJk_7BS)B(`U}yS@H4FQt#<p%yqMt zZ4A2~bGYzMr?9%4yZd7q>AwDc<^P?+b(2)`@9nAl^(AxnT{{bl6#*I*^RB=CDs7$@ zvij<ZeU_yOpDwz~Pn|x!du|C2Tl1k)ek)e9aPId}tNwN~-G9EF@1&HhtW^c-{cejp zHy>kDc@@|hwmNoGO6QHcF>&j+FJ9dIyz+^CVc*ZMRevx0+waZ3t~ck2`@hI(qO<R4 z+ANdZYSMitpS|x1^O>FV>OU3lUBBL6X`)20Tc=CYd8P(S!MeW3t5&Vr_vh2;MT-{s z&NeeOF|qmmX7dUAGiQ<~Te!<x82r5U@O#zX*w|Qqn~yI3{{C)m$8OxX@!&y1S((`? z{<JB5eSO>S*ZqEX^zr+|?YEzwo!#E`OAOR#KY8-x_Po1NGBP&B&w66?j`PURXmoRP z)99-D^YQpmHLtjxMXcU_HM>7dR@s?$cGmj+|Ez>M4R|)^-``iQ_Oqv_CuVQe)-78~ zKHXd+EG#@-KVDBq=gj%@>5<<~P1Sx_P;s<N)FMJ)bz;b&Eg_4&mR`!*YAEb?d5hQ5 zPZc&RR^$u*3(zR}^(C`Oq3rFgsne&IpEv0b&<F_)743EV{rmU)nopjKFG}>ftzNyF zxv}AHUiiw8!-o&=-Md$By7%IXI#F9P_^xfb{kF_%ZXusVds|xz`y%EuYd);L`fB<7 zx?KwwK3v>yw@4%F?ygepur)LOaD1q+X>@pyZvXq{`?~MD@7;@Ad{KgfMNLgDuI}ek ze!CwFR<C}2ZEdv9=`533bLPyc-e%*j)>8lP=kxis-)7#->9Z`2SDLtG+cvw;XN+&i z?tgu+Cwkug{>1%$%d5X!bg#9$|MBth*5{ReVOy@h7Ilj>@%{a`?xE;IF_W1-YIjz~ z#l)Q1^k%8|^lka~^_J8Y6l_?z^5pZ+l{WKQ&exkr#qO>8x+(Q^l3e#ClfNI2%RhGc zV*cr84KFY6#f*?O4$;xl*J|fI`><IjIzB!=I5^pCHmFH`=+L3vk5^sI((Fo-P?PHA zdd{>ZYHf&Cs)U*hUwT@an3&kQ*xh9X1sk?)D=Yeyt|BBUFaQ1b-{L2Q4Kl|&efyO? zg?7LB`{L!xpI6t{ZOyo-w2^Vj-Mr%~Uu1IIpWbw6ZPeShZ$Cdfd;0WgZWbn4S=q|U z%E`rhCQqJxHS4SO`#p=Vzg`=bU0hro7&!4_M$PlN<v~F~U0q!zR(BsBZdVmLd1|V* zdOp{QQ>Uul?R@^H?*G>8>la=gtgUN!_WXJN-Cdz?QtE<(gUid!wX&)Xoj35w&(DvF zk~&@(8ykD~?p>YJSzB*CpI={B^wMso&$lDO{&#kjYOAZOo0^)6aGgxqlzV&I)~#D3 zb;OzvF1Y+sX<|o+maeYuTq`-ZPY<J?&QF{%<Dqz-t%Im<^pB@Sm6eq{FTV^~8KS@U z%OtO*Tx`wD{pND9HJ6Kf`}xIf%bEG1G%amefefgEJehpUU9OU)l-J;N-_KmL+wJmo zH}2fIbM@-d01c;w6AJc<l(J8F@bLV(b9Ik8)jxguq&8n}_RN_puVw|7GjPh)ZH?Mn z^YhcRY191eezq)H;h~abHoN{~cl?7bS_jsY#ee_Y-_uj`_v`iF-`;MHTFcHSqfk&T zazKW2e~6Z;RPWE9KeeWM=}n)k(#d&=p;+mU)!e+Nr=|)E3$G4a`|Ho=^Tox*moHxi zH5O~moG-j{;lhOLueV06<vDyJWz$^i@>gH0d={~JeE49@6C56X{n90+i5?!4MC2wX zna%c96ZZSTs8aN!bzR->Z*O%@^YQRZP{}lq$e494!(@eZ1B?B$=_gZ)cJA4>?VJ7o z&-SZVt!is;@0YXfDt*i#WdDc7v10GNbLY;<T9<h&4cdIu#>mLX!lGjrv&WOf{SFHQ zR$P5`?%cV92M-oMKX)?4Xs%!TE@qEE^WycUzrVHhbkfEQlUWG{KfYY{Pp;AjHEDSc z-^ejre|>l6<z;twmkYBPnwW_2uub(+UB$03@o@dqQ&U%mum5Co|Jt=}wZFfuTD5B9 z#*NSC*ULR*_jvNbeep$U^Sn1VHXcqe`15J{{+z5VEj_)uXEW2kRN21b1GU}x+MO2) zxCRETobq_bQt#>iejK-7roko3Zg9KyFsFUr;}-8<Hs_;triHE!Q~b$Lyy*FK50$$8 z{}=b$1+Bhno`0{$ZSl&LE35X_eSUU!#uN4lCqN~qzs<)MgN@-4UER+sA4c9?Vcp=u zXYU%=Ev7qbc6JWqnU~3+5hdaB56$Vq3~hfoPrfY+4-GvUId$*m&BCiw84vw$sIiML zFW-JNY37_i!W=9)X0t!s;D0!^vy=0oU<3b8{VliOw)4x!?JQb)gDIb{o%yr?!=e8Q zN)u0<oUC45Rn_D6_}$&zTcdOj8<?7!zJ2?4<;s=2%imvn{ngpo`Tf4%@BHgNO>Syx zYX2kt$!7lCxqH*jN^NAlcO}bItb$qQvpvW9>(+*bA8%!^H{>Y>k4!azve2L3`~O$B zIwfwtx#(g>Zf@?Gr8_jcsyJR3b93+MoN3Ly=cCQ}LK%IgM2GYL*Y1qbYfEg=Jdn3N z+Tsjf`(YE`(@%@G-`3?}6w{BZDL)shH~ntj_o}@I6Fw+Dk+1u@I=-~LyxaG}gUYzI zVgEnd|Nng0UavV)rfzGL?wcT<!yN4Av$jTQP5op8?w!o9`=xoj5R_skr>3TIreAMw zYuoqh)#?O;7oUG#;Nd^`_V#vh-KZ(EW=U<HoG$U~NT=|{43UTKKlZb(4bz_L#V>1h zq;SsBq?fN=ojP&iLWW8GpU3itAAWdsbu~9P_wnPPF}%-n=E!tD(Px)B3I=xb-*3Gh zcX-BU#R*<ZPo6v(wKh!WPlxTH|7$fxx=x)s)z;S5)x|aW<dd@9nX~R~%Z<*>&Gq!` zG|;p#HxFNbUAp(!$q)YTiaqQO<nY>qo3#FRKcA#b_Y-J|TYrCR_Vv4|MMXsccNvV? z(|#}#Ij#j(=6^e0;~=|CLVIW8HT&)MQoZ+f7OPA3c8PAdnNy)-f5(3J-Fw%ri9KJe zXl)(6GDPW*y-oY!kK5~iZ{N9dr{R1Kmq|}fobV_rGWwReLte!bG!(c!@2*hv(}lZt z|L!%v7qPd>^w9sq$r5VX+OKD(&lAjE+t=5(I(&W7_O{<!s=mHDE?2GdOvvBFSKhwP z=A41>!}=Q)^U@>D(tfn6Urlar`+dAn=JY1R@L~l|qlsneb9k6%EEcHyv3l_m_6lx; zH|;ldg*v}{`J$q#dbGw|gsb&%;+nNBADkB{dKMKFe0aP4{<M=RhTJZTFE%zZw)~ei zH8qXhS)}U6xH3d*O?vl-^S?e8Bt59KQ&mlUe{XM+ZM}iSpU3k5J4D0wU7Ts0{-&%t zE^gk9r^`P-KfgX=Bh$nArYHYjp8xO4y?c6QQx$|dZT|oH{PgKl&JThLWoFVF_xp>u zo}F*Mf6W@79M6i`XQu@m{@2*pc<a`!R&H@IQBltIJpBCgZL7C!*|KHLnlq0-)_lDh zuHu<@XGfu0%>!Epl{0Cd|NQ)Xblu;$Jrx^w@3v+<#DBTzuf5^@xt8MG%N73|OxUn& zncLd1`L@+ztFJCwy3|!^;;dOxGkwCs!<S#okdl((X!`K`Z)j*}_4jvkd!1igxf0TS zR7vdL%4`8YSy=@kgU4-K?$-+EZMT-;dw+9t`=S;1?!_rS&)Z)8{@z}x-eYN-r%s#p z?(XjI7v1H1U6j7pyzyLmDN>N<-)tWrAD+(Q-FI(XO;|RwZQlL&-?^1#W-V(zsNg8j z=%66g`^m=tvdQU9si~=DyZ=5q+MRuE&BB-a{~Wn@@7}ImyBriA6zxo_KJGE;$-~3# z`mwu2(z`yMn`^ysJ7=-sV|jzc)1;)OckkZ)SmZ*6$!zm{vE6!~0}juhG|6dFiiJ#{ z+hVJ^eF_}l9N4OT*lO;&wQJWdTb6cvTW)J>Yx(z|QoU|U6IG6Nelg9ywkCFW*qa>> zj&urJB)SD&nW`QB@7?=<erp^|q+<6}eDv1eYjRxs)#HA9H4dls*Sp^uhp&%|-C49W zZvFp<hu2@s2nr7V|26)<sk*wlw)X0c8#iv*Vq$FkdF}Rlo1)f6Mn>lE{Tikqz|nq~ zTU_tXhQ#IxWt(sANj}cE|9<_mGc%8Huz5~0Y&WoYAYLGoZZ_LI_m)c8#U=aq?_a*0 zT~u}YX>BbnBV*&_Fp=}0%XZgBDH-!VobI*My6nx06)Qaa{ja|)sjRHzYEAn5?5wM+ ztJ-AG<(Kz<yOk~1-~QNQZ(O~<P|ITGE#GAndA=VxG=Itzlgbc_;~RBO8}vl{Sgvh! zIrzHP)KyECxcs=4V8D^Q=VbVrFzs2w3Cj-Nm4Xa=8@~?kskU^`nz~4ov2H{1zxVvE zfw{T4?EG>f+6GouT0VLV4J};z3zCABCU(qKQY+BqRR{z{MNnX%qS(KE`}Y0&S7)N) zu&8zZkNuVllO7)bY{@9cbM6~6xJ&_$+SRN6ySg;8<Spm-K!zIY<m6<(<;H0zD(8K# zuvxisC5OGkqK6jm_I|&&dfhs)-G8oJyY}tP=JQH_7&tAS#qY2CJ4w|$$!=1|vX}OM zU;1x;s#n@#4;l$|P!L$|U?JnC%Xnyh!@bJqbNl-EmIi5Fds|Xcl5=Ydrzk5&{i2V* z|3+`iIeFrQK=q%~^8Y@tpJ`)hu{Z2@Ju0WfAt1c&Gm<l5(*X6xZHZFS()suHbRMnT z7aV-HG4z1&v$ma)7pL$)wyLkKtql$q1`T6RpE_0X7{7uD*Wcsyf86J6m0TaQGbk?3 z?)K#OA1mIJ?T%n<KRl7)^OSwn!IM-hb^X`;zjye2VN81Z^ZvRo%DeB@{r&az(xpqg z?Qdkvn&zP*;(9b@_DmJeu0<_ON#=pRVjVv#HTS6gk^X#L_+Ia4<z?FsnE&HTV$GPP zr>A%B)G488)<56g-Y%?TpZ8q-b>y0cfSHAL?Z0&dHb?KCzif)v((CJDt6#6(e&pNI zix&gu`l)Z5cV8yct4YB|?)*aMb`z=I2-nQ5x8_=x*F8See!u$1;fEXUzgPDRS{U%- zZ(X9gGDlKM%96c%?>_&`%fn-0YTEhMP;dI_mnCug>tb{IB_$;bEo82*j~8EkYTv$n zjg5`3udhG8hqrr?#_Y3Z78Vt6Z<%gnx_kF--F|z&#(DGPx)y<~WZZrC-PbD3E+Op; z_wV}$hNuV$YCkBk;$>?N(GvY_d^fK=JA3uvhXS{g+1S~mqoR&nJDCz$mXYz|_4@tO zPCqr=Z!6Tv!^>-GZr=U&+QEc^jEog4S9<2GeDpihtJf_!C`jnJ=h?Y)=N3vO^_eU^ z{BXtEwW7QGn;-A^`0=A|^tL}A9!@{~)YH>b=6I`<;#4owo#_>O?|u9B%|YRSK~K<1 z5o@j>4UwRgAqxYJ+_dw(oV0sQfP>c5Qz@I+^%N$bRGR29hbd^~lw~h}L{B*V^yBsq zy{sulk#m@wR69aN&VLqh)fC~{$fR@nl8Nl{h6|}6UToL%%7sh!c?SoHi0+rVIK}4t z>Z`9rwZl5T{?R#o?b@|_=YMW}Z~I56bIF1Q51RSy0yIQchp(T<Qy&+1@3j8@H=lpH zxx2^LehuB2FE1&{$=1An&!?^k#)pfo{2H%ayY}kUD+|_FuV3fi+3|7n{J%bH97;>S zzIc%_N8RMl&-3+R8Y0$ZZv?a#1ZWf$7hhi+E&hDYi&dek#dM=o!VbJGv;TS}*wxiF ziM6e*?c4kN`5PmSaPjc){Q0un-q+Jp5EM)QKb_Xso_cD=d$+}b%P;?YwR(M5>h0&B zdwY8qYRdZs@B8tnyKvU0b91e~7Z*KAobv(HRZTUT8MSs^)wce}J9>I}`W`=;^WS9l z*+MhFz>un{syR$XGtZ<L9o1YAqV;%Ats;lh+OXp?hwj#Ph(2$gqtJ2XO2||%(d7*X z6FQ756giZ1b#?z~oXasgzS4Q#^P_n`X5UF|Z4=NwuqnsQjqR{OQoZJ^qGu+lX=%%D zT)Y`C>-l%X^!qKWmXEF+-6Hb9LeDR@Kt{c%OMVB#=}ju0$1*p(k84Pj*f@FC<p_m; zev<ncW)+E<KJDSKXZRCfa2PrTx9?-f(KYw%4&-p{KmXji>Pv=+)Zcfre|<WwzyI{A zd%C*1?EG>i7Bc)F_AU%~vH84Rw~JEYsSP@}FI;#~w)-eoNlD3#9J7t(?d|RUb1Ve^ zU$?0KmJ=R+UFQDR_O`ZFt5!WL;yp7Z{l`a}`xh?;#>VDujL_27UVg41LE_n?qusT& zwM&;SeSLj>f2G;f)SLSI|7=>nKL7c-xrX|a&CJc?_f~D)yVus-JX~jvd!Nihi@fje z?i#Lt!P0#2`@L%al_9IHzM2tTurmfUuHd#<Q(u36mG1P^o5zm1wI5!1HLLvXE!Axk zJyeALNBPZ}e9~_I`LxZwy}hw}t4g1qntJl&$>7t_meikn$BrGlcQ0<P-}124yLas> zdv|B%#EFIehV6#~<Ky2KScI*K*jV!N(u}p0|Ni{EcI}$_{2HS)=aSOW*!^{PpBBBn zwN+bJS2xXB#=6W$X<|xx`td)43j<z!d3pI@!iG(oin6?04?kSBYSp`U@4mjit{<^M z;aTU$wzjsz?flcHPxt@J%-OWzW{yy&im~zLojWUEURoNgFW|EH;<RbgSh>Y``1#up zKdk<?!a?D}#fyP4F?Vj<u*kn>v;Y2igEO|jnU5FB%F0&lz4x%-$<wF4xteW>dH46t zojLR7-Me$APF;HW<uWmg+FxJJ&NeSDDk^((L-4=S(=%^Db82ti#O$fqc==_|P0fia zlASI^MMZgcb|_xU=9Eo~i;GK7e}3hIg-l;tTic>VN^OZp>>9GNvN)OoR)#G1pWi2G zzcM6iV}zJaguv&;jgNN(FZWxze7W`9bKK&39jv#rw)XY)-P=*9oW|JqcwOAyS6{1+ zzFM_=_wR3SZ!gl-n&{)>GsmjbYi(HfS)s`uDu$mQ6z%kzV=-~^<l>KyT$f*-IcHAI zyE{8)9Nba#)XUTJ<ju|L$$DZJZr{${e!IJ?t54QiZ1aJyudnaky?brgYw`FR!OfO> zF*_c7tl(&}D18-jrtL%3UQ<(3v2N98x_Wcx&NZ8zdvcO$`MW!U(Hj&%@%4n|?c2Aq zva$ygKK%Ll*>E|VhsvaN>-3gizIp4Gm5GVT*SqJ=om;nV-Fds;Yj*C8ym949?5)>d z<?L#9Y~CEaX6dhAzw++yyL<h*_+}v$A<x3XjVDvM*qT4S7nyVM;quH~ixw?fx^(Hn zg^D6vM|)ff3qSVBT5sC4>DaMjNqI}QZ{NOSN5$)FYo*O{X6!2N@9R62vT1Afb-kD! z2G6F(&3hgl74_=%YiTJdHg@*pa}^6SZ{?V!r>7s^(<jyGGRN=vs?gP8>*Lm5&020I zasIQ~<d+|h%b!1Y?%U6rLMEBz>-K%r-0Qde^84@lF*`ooE@K6E&bMY?7ZVfHi`?{N zqPv`+kj2;Q(HjyP4NmK(l|VYf&(6-SocI0rU&GafKR-Q{HqZM~VH14#WZ|6$4<0-^ z+I@X(bh?SuQ8q_ONlEW%I-QdL)~s2xWXY0Oud=!p9m#7jmf#6n9h&pO^ruP6#%&8U zwCwHoZ`@dzl$7*Jz<*&thRG~x^E?p|k&@C<&f4Es<O5@3ayH-Gw0U##HWA;;R&&=a zU8<_7>ACvqv7C-6Q$$*wHs;>m_Iu|Bd*{RNKmWA*_v3Ns>aeNPrX73prA6Als=B(p zt?h`NnyFOphK{7*;LBIaCr_I6r*8k{mwSqz`<;oMrsBEz=ARqM{cmq>UcP9NQ;rtL zVS}X2M>1xGX-)N8zIpfV+i%N`_h=k1lsSHMe!AKj*UAmEMC??>^<r+^xS{ba_{cW> zGm8W{g7Y4UBu9qjxGlJt!NbC|ckkYZ1s2cp&Td+BH}C!H*OxO)f}bDuR1s=EXkcY^ z>-u%|u-?h0lAm?^k8dt`cu4;53-`5a*CxqtvN_*=IB}!aq|;C3`qN8FOwOfmxtf)m zlk=s*#xVWXv!_ovlmA`3c(K4j=Cj4?Z*Ol`R#yJ~`!`8_^O~^i@bKv;Q@Vai9x?FA z&CPXlYm3nnmp*^4>4UaNS5s3HXoM{F=8VnCOM^1Y%D%PB*R8nx^4a<M^2N%pudRLk z^5xI<|9`EYp*w5t+_{q{f4+VHUzpzX<9jrlR8F2c<u&_k*`FVU8#UiKwHtqZk!|!R zdRvZV(G!o@*w{1sn-;COb0?;2(WOh5j;Jk~q%w2zWZ~!H3XkIW0#=4pR#rZJ`t)JJ zji*INbtcc8DY;oaP;08CrKO4|SL~vwwcDcB26r!AvV<czpt!g=xy-`V)pcROi~aw9 z@4vn-R=PMwccRCv*|Yg&t+o_BJvAdbVsl#W*|gtZF8eROm~rNV_tHyu?!;`&i`1HW z?b@|{|Ns34O$yGmYEtk~6ZXBlckf=q`)gOM5ct+|=#bOK`AH^H-QC^dx=|vZ&3*j+ z&!0ap?)O(GZcoK4w?!9UoH%hJ*xz<(h}KcI%~o^utgWMS=Iy`#et*%^Qxlcl|GmBc zPxqW<!bQa=XLhbS^0~%DO7vZaSoHrHsW*QJOSiuB$XRmy^Bx0Jqkmt{SVSxQdw;Eb zW4ZratJ05;T&H?{J!5?S$@AykwYvk}Cf)A*tUSl>`9kM*Ep2UWEv-lY+Y0Mk=DhW< zTOXj1cJid|@tb`HCIYLEO;-0;Q&n9Xv(w1WcC*gy+qbKqote4+=j{DIx7D|Pc&l^z znEi)`7JBClrx<+b+`qr}v7YSyX^*yxod3Mse?A`z)9vl~{l<KvZT5#28>VId5N<yG z^i$Pducem~3~J<W_q!;?tv6Ryeah(f;f&0~f*C3&^KDcQZpyKc>8n@vP5NA6V>DCe zT<wMXtcUmw+!Nd684mF`%sk3rf5umD`s?re|JTl0&cJnf^%1!a4i5V>VG})`%)2@H z&{K`XRsPAzk2{6cW%!QE|NGGX?_XWtW2VLfA3kg_(A1XTsj`uqe!6wz;T*@sTo2Y) zHSg9_a#?(_`1!f3SFcV~seEt%G)ORQ+O&Q9_MM)t|Nq<e{k1QbPS=asapBsvw5?J6 zG8P3dE-ajFo*xzx^5*`2`+vo27;Np&l<>7b{`2#5_O&&E8X{M(UX9+Cb8~O?_u2XT zc9y-pbv?d*@7lGwDJdzBkM+)-J9q8cwQ=jqe|~y;-v0le?Q?^9Ui?fv#>v)fo_9w; zE@}Ss>FQ@Dhiiz4xN1&4b@3vow#_ifGMd@KesTKLsb`;Nf8ww|lXs}4GI86?pp|!a z6h7|O-)CWCvnD_z$1K`HM(o|C&lNUmlQXZciv{)I^B&Lqqc=l$Mf|@{(^s$x81NK- zd2#XBv17*R=jK=ztJ&M%&oPs?tJ$%4@7^t2Of)rL{`mN~(V;=*<f~V&PMtb+@ZiCI zyI&_>f1NgU>ep}Io;`U|<NsOe;qL~?x)1*==6(NJGr4@m%Bxu`LtcHXSQ50-YpKw^ zsU9jOzU<A8Yr{?(^xS{%@8vbgYw1LfCydLcGauq-;Fq>r&IntThrA>w>{t9xp2L1K UFVtBuFfcH9y85}Sb4q9e019!;jsO4v literal 0 HcmV?d00001 diff --git a/Excercise_3/Cryptography.ipynb b/Excercise_3/Cryptography.ipynb new file mode 100644 index 0000000..c575144 --- /dev/null +++ b/Excercise_3/Cryptography.ipynb @@ -0,0 +1,483 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7bdcd773", + "metadata": {}, + "source": [ + "# Introduction to Cryptography and Letter Frequencies\n", + "\n", + "**Cryptography** is a field of study focused on secure communication techniques that allow only the sender and intended recipient of a message to view its contents. **Substitution ciphers** are a basic method of encryption where elements of the plaintext (the original message) are replaced systematically to form the ciphertext (the encoded message).\n", + "\n", + "In this exercise, we'll explore a simple **shift cipher** (also known as a Caesar cipher), where each letter in the plaintext is 'shifted' a certain number of places down the alphabet. We'll also delve into **frequency analysis**, a method to break ciphers by analyzing the frequency of symbols in the encoded message.\n", + "\n", + "The first objective of this exercise is to implement a simple shift cypher using python. Afterwards, we will try to break the shift cypher, by analyzing the letter frequencies." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "595a8870", + "metadata": {}, + "outputs": [], + "source": [ + "# Setting Up the Environment\n", + "\n", + "import string # might be helpful to look at\n", + "from collections import Counter\n", + "import random\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "ed7799e9", + "metadata": {}, + "source": [ + "## Implementation of the Cypher\n", + "\n", + "Let's begin by encoding the message. As described above we aim at a simple shift cypher, which shifts every letter in the message a certain number of letters down the alphabet, looping back to the beginning after the end. For instance, when we apply a shift of 2, the letter 'a' becomes 'c', 'b' becomes 'd', etc. As a result, the word \"at\" transforms into \"cv\". This applies to lower-case letters as well as upper-case. We will ignore special characters like punctuation or white spaces for now." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "caa9910f", + "metadata": {}, + "outputs": [], + "source": [ + "# Encoding a Message\n", + "\n", + "def encode_message(message, key=2):\n", + " \"\"\"\n", + " Encodes a message using a shift cipher.\n", + " \n", + " Parameters:\n", + " message (str): The message to encode.\n", + " key (int): The encryption key (how times the letters are shifted)\n", + " Returns:\n", + " str: The encoded message.\n", + " \"\"\"\n", + " # Put your own code here\n", + " \n", + " return\n" + ] + }, + { + "cell_type": "markdown", + "id": "7efd44c6-484b-47ee-9472-6b3a36ae9fc4", + "metadata": {}, + "source": [ + "### Testing the cypher\n", + "Now let us quickly test you encryption. Try out some strings and some keys. You can use a single letter at a time. Think about special keys: What should happen if you use 0? or 26? Does it work as expected?\n", + "\n", + "The `assert` statement can help you here design some easy tests, like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "45f1c38b-3650-4209-a288-dd5dbc004b94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "If no error occured: everything worked as expected!\n" + ] + } + ], + "source": [ + "assert encode_message(\"a\", 0) == \"a\"\n", + "\n", + "# Add some more tests to check if your encryption works\n", + "\n", + "print(\"If no error occured: everything worked as expected!\")" + ] + }, + { + "cell_type": "markdown", + "id": "df31d050", + "metadata": {}, + "source": [ + "## Decyphering\n", + "Since the purpose of encryption is to deliver the information to another place or a later time, we need a way to get our original message back as long as we know the encryption key. Next, implement the decryption function. In our case, it should be somewhat similar to the encryption from before. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "91d2ec6b", + "metadata": {}, + "outputs": [], + "source": [ + "# Decoding a Message\n", + "\n", + "def decode_message(encoded_message, key):\n", + " \"\"\"\n", + " Decodes a message encoded with a shift cipher.\n", + " \n", + " Parameters:\n", + " encoded_message (str): The encoded message.\n", + " shift (int): The number of places each character was shifted.\n", + " \n", + " Returns:\n", + " str: The decoded (original) message.\n", + " \"\"\"\n", + " # Put your own code here \n", + " \n", + " return " + ] + }, + { + "cell_type": "markdown", + "id": "a1974d1d-703c-4e7e-8636-4047efdc9a91", + "metadata": {}, + "source": [ + "### Testing the decypher\n", + "As before we can test our decoding algorithm by many statements. However, since we have two functions know, this might help us. Can you figure out how?" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b63b9859-0b69-447a-a39e-b5ca555d0348", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "If no error occured: everything worked as expected!\n" + ] + } + ], + "source": [ + "assert decode_message(\"a\", 0) == \"a\"\n", + "\n", + "# Add some more tests to check if your encryption works\n", + "\n", + "print(\"If no error occured: everything worked as expected!\")" + ] + }, + { + "cell_type": "markdown", + "id": "261c284d", + "metadata": {}, + "source": [ + "## Breaking a cypher\n", + "### Brute Force\n", + "As you might have noticed already this is not a particularly strong cypher algorithm. Since we only have 25 usable keys, a simple \"brute force\" approch can yield a result. This could even be done by hand, and certainly with computers. That's why it is important for modern encryption algorithms to have a huge number of possible key. AES for examples uses between 128 and 256 bit keys, making the respective numbers of keys 2^128 - 2^256.\n", + "\n", + "The following code produces a cypher text with a random key. See if you can figure out the key using brute force." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "cabfa50c-5366-4728-af0a-18791b558fac", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Key: 1: Zkxtm! Rhn yhngw max vhkkxvm dxr.\n", + "Key: 2: Yjwsl! Qgm xgmfv lzw ugjjwul cwq.\n", + "Key: 3: Xivrk! Pfl wfleu kyv tfiivtk bvp.\n", + "Key: 4: Whuqj! Oek vekdt jxu sehhusj auo.\n", + "Key: 5: Vgtpi! Ndj udjcs iwt rdggtri ztn.\n", + "Key: 6: Ufsoh! Mci tcibr hvs qcffsqh ysm.\n", + "Key: 7: Terng! Lbh sbhaq gur pbeerpg xrl.\n", + "Key: 8: Sdqmf! Kag ragzp ftq oaddqof wqk.\n", + "Key: 9: Rcple! Jzf qzfyo esp nzccpne vpj.\n", + "Key: 10: Qbokd! Iye pyexn dro mybbomd uoi.\n", + "Key: 11: Panjc! Hxd oxdwm cqn lxaanlc tnh.\n", + "Key: 12: Ozmib! Gwc nwcvl bpm kwzzmkb smg.\n", + "Key: 13: Nylha! Fvb mvbuk aol jvyylja rlf.\n", + "Key: 14: Mxkgz! Eua luatj znk iuxxkiz qke.\n", + "Key: 15: Lwjfy! Dtz ktzsi ymj htwwjhy pjd.\n", + "Key: 16: Kviex! Csy jsyrh xli gsvvigx oic.\n", + "Key: 17: Juhdw! Brx irxqg wkh fruuhfw nhb.\n", + "Key: 18: Itgcv! Aqw hqwpf vjg eqttgev mga.\n", + "Key: 19: Hsfbu! Zpv gpvoe uif dpssfdu lfz.\n", + "Key: 20: Great! You found the correct key.\n", + "Key: 21: Fqdzs! Xnt entmc sgd bnqqdbs jdx.\n", + "Key: 22: Epcyr! Wms dmslb rfc amppcar icw.\n", + "Key: 23: Dobxq! Vlr clrka qeb zloobzq hbv.\n", + "Key: 24: Cnawp! Ukq bkqjz pda yknnayp gau.\n", + "Key: 25: Bmzvo! Tjp ajpiy ocz xjmmzxo fzt.\n" + ] + } + ], + "source": [ + "message = \"Great! You found the correct key.\"\n", + "key = random.randint(1, 25)\n", + "cypher_message = encode_message(message, key)\n", + "\n", + "# Your code goes here\n" + ] + }, + { + "cell_type": "markdown", + "id": "3ad2956c-aba5-4d92-93bd-1080d5064f10", + "metadata": {}, + "source": [ + "### Frequency analysis\n", + "A more intelligent aproach to breaking a cyper is called frequency analysis and uses statistics to find the correct key. The concept is based on the fact, that in structued data such as text, certain statical effect emerge. For example: in the English language certain letters, like 'e', 't' or 'a' are used much more often than others, like 'x' or 'j'.\n", + "\n", + "The letter frequencies for the English language can be found here: https://www3.nd.edu/~busiforc/handouts/cryptography/letterfrequencies.html\n", + "\n", + "In order to visualize these frequencies for a given text we need to count their occurences. Write a function, that counts all letters in a text. It should return a dict containing all letters (lower-case) in alphabetical order as keys and their respective amounts as values. Ignore special characters and white space for now. The second function should then be able to visualize the frequencies in a histogram." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8d4767f6", + "metadata": {}, + "outputs": [], + "source": [ + "def count_letters(text):\n", + " \"\"\"\n", + " Counts the occurence of each letter in a string.\n", + " \n", + " Parameters:\n", + " text (str): Text, of which the letters should be counted.\n", + " Returns:\n", + " dict[str, int]: A dictionary with letters in alphabetical order as keys and their amounts as values.\n", + " \"\"\"\n", + " # Your code goes here\n", + " \n", + " return\n", + "\n", + "def plot_frequencies(letter_frequencies):\n", + " \"\"\"\n", + " Plots a histogram of letter frequencies\n", + " \n", + " Parameters:\n", + " letter_frequencies (dict[str, int]): A dictionary with letters as keys and their amounts as values.\n", + " Returns:\n", + " None\n", + " \"\"\"\n", + " # Create a bar plot\n", + " plt.figure(figsize=(8, 6))\n", + " plt.bar(letter_frequencies.keys(), letter_frequencies.values())\n", + "\n", + " # Customize the plot\n", + " plt.xlabel(\"Letters\")\n", + " plt.ylabel(\"Frequency\")\n", + " plt.title(\"Letter Distribution in Text (Ascending Order)\")\n", + " plt.xticks(rotation=45) # Rotate x-axis labels for better readability\n", + "\n", + " # Show the plot\n", + " plt.show()\n", + " return\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "a1fcf1a0", + "metadata": {}, + "source": [ + "### Using the frequency analysis\n", + "\n", + "You just built all the tools you need to systematically break a Caesar cypher. The text document `shakethatpear.txt` holds some example text. Load this as a string and compare the distribution to the normal English distribution shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "f8168f9a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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rpxFRETc8nq6d+9uib2c7N+/3yRZUFCQnTp1KtF1199XHTt2NEnWs2dP97K4uDiLiIiwDBky2OnTp83MbNWqVSbJVq1a9bc1b9ab2bX7c9iwYe7zzZs3twwZMtjevXvdy44dO2ZZs2a1Bx980L0sfp8JDw+3uLg49/K+ffta+vTp7dy5c4leX7xhw4Yl6EmSZciQwfbs2eNetnXrVpNkb7/99i3rXe+zzz7zuG/++usvCwkJsa5du3psd+LECQsODvZYHh0dbUWLFrXSpUvbpUuXLCIiwoKCguzgwYMelw0MDPTYR25l+fLlJsm+/vrrRNf36NHDChQo4L4fly5dapJsy5YtHtsFBwdb9+7db3o9V69etcKFC1uhQoXszz//9Fh3/WPUoEEDK1u2rF26dMljfY0aNaxYsWLuZbf7GJ86dcoyZMhgERERHtu9+OKLJsnjfkpsv61Tp45JstmzZ7uXxcTEWGhoqLVo0cK97I033jBJtmDBAveyixcvWokSJRJ9Llzv3LlzJsmaNWt2023MzB599FGTZFFRUWb2v/20TZs2Htsl5TaPGjXKAgMD7ffff/eoMWjQIEufPr0dOnTIzG79WhFv7ty5JsnWr19/y9sBMC0B+Btmpi+++EKPPPKIzEx//PGH+9S4cWNFRkYm+NdoUnz22WcqWbKkSpQo4VG7fv36kpRgZKZOnToqVapUsm5TvPjR47/++uum24SEhGjHjh3avXu319fTokWLBP8KvZUePXq4/44fLb98+bKWL1/udQ9/JzY2VkuXLlXz5s095hzmyZNHbdu21Zo1axQVFeVxmW7dunn8q7127dqKjY31+nBX4eHhHqOg999/v4KCgrRv3z6v6knXRjPPnTunNm3aeOxf6dOnV7Vq1Tz2r8yZM2vmzJnatWuXHnzwQS1cuFBvvfWWChYs6PX1nzlzRpKULVu2BOuuXr2qTz75RE8++aT7fqxfv75y5cqlOXPmeGwbEhKi9evX69ixY4lez5YtW7R//3716dNHISEhHuvia589e1YrV65Uq1at9Ndff7nvizNnzqhx48bavXu3jh496nHZv3uMly9frsuXL6tnz54e2/Xp0+c27p1rsmTJ4jEvPkOGDKpatarH47548WLly5dPjz76qHtZxowZ1bVr17+tH//8zpo16y23i19/434eP2ofLym3+bPPPlPt2rWVLVs2j/0vPDxcsbGx+u677zy2v9VrRfw+9Mcff9zydgBMSwD+xunTp3Xu3Dm9++67evfddxPd5tSpU17X3717t3bt2nXTF/QbaxcuXNjr67pR/FEJbvWmN3LkSDVr1kzFixdXmTJl9NBDD6l9+/ZJ+uZ9UnpOly5dgi+0FC9eXJLu6JEmTp8+rQsXLui+++5LsK5kyZKKi4vT4cOHVbp0affyG0Nf/Jvvn3/+6VUPiYXIbNmyeV1PkvtDSfyHpRvd+O/dmjVr6l//+pcmT56sxo0b6+mnn/b6uq9niRytYunSpTp9+rSqVq2qPXv2uJfXq1dPH330kcaNG+c+qsCrr76qjh07qkCBAqpUqZKaNGmiDh06uPeVvXv3SpLKlClz0x727NkjM9OQIUM0ZMiQRLc5deqU8uXL5z7/d49xfMgtVqyYx3Y5c+ZMNNAnJn/+/AnmI2fLlk3btm1znz948KCKFCmSYLuiRYv+bf345/etPsRev/7G14Mbn79Juc27d+/Wtm3bfPL6Fr8P/dOOEY2kI9wCfyN+buhTTz2ljh07JrpNcg6xFBcXp7Jly+rNN99MdH2BAgU8zmfKlMnr67pR/EHRb/UG+eCDD2rv3r368ssvtXTpUv3nP//RW2+9palTp+qZZ565revxZc/Szd/cYmNjfXo9fyf+EGY3SizIpUQ96X/77wcffKDQ0NAE6288akNMTIz7y0l79+7VhQsXlDlzZq+vP36ucGIBPX50tlWrVoledvXq1apXr557m9q1a2v+/PlaunSpXnvtNY0bN07z5s1zz0v9O/H3Rf/+/dW4ceNEt7nxuXAnHpMb3enrCA4OVp48eTzCcmK2bdumfPnyJfjAk5znb1xcnBo2bKgXXngh0fXxH1xv57ri96F77rnH637wz0C4Bf5Gzpw5lTVrVsXGxio8PPyW295qROFm64oUKaKtW7eqQYMGd3VEIjY2VnPnzlXmzJnd34C+mezZs6tz587q3Lmzzp8/rwcffFDDhw93h1tf9h0XF6d9+/Z5vOn9/vvvkuT+8lz86NC5c+c8LpvYdIDb7S1nzpzKnDmzfvvttwTrfv31V6VLly7BB420IH6aQ65cuf52/5WkYcOGadeuXXr99dc1cOBADRo0SBMnTvTYJimPd4kSJSRJ+/fv91geHR2tL7/8Uk8++aRatmyZ4HK9evXSnDlz3OFWujZF5Pnnn9fzzz+vU6dOqWLFinrllVf08MMPu2/n9u3bb3o740d5/f39b+u+uB3xP0qxe/duj/84nD59Olkj7oldz86dO2VmHvf/9SPet9K0aVO99957WrNmTaLP9++//14HDhzQs88+e1u9SLd3m4sUKaLz58/75P7ev3+/0qVLlyAQAzdizi3wN9KnT68WLVroiy++SPTnH68/LFD88R9vDF3x664/5Fa8Vq1a6ejRo3rvvfcSrLt48aKio6OT0X3iYmNj1atXL+3atUu9evW65TeP4+dMxsuSJYuKFi3qcZiyW91ub0yaNMn9t5lp0qRJ8vf3V4MGDSRde3NNnz59gvl677zzToJat9tb+vTp1ahRI3355Zce0x9OnjypuXPnqlatWmnyG9qNGzdWUFCQRo8erStXriRYf/3+u379er3++uvq06eP/v3vf2vAgAGaNGmSVq9e7XGZwMDA236s8+XLpwIFCiT4BcD58+crOjpa3bt3V8uWLROcmjZtqi+++EIxMTGKjY1N8NzJlSuX8ubN694PK1asqMKFC2v8+PEJeosfAc2VK5fq1q2radOm6fjx47e8L25XeHi4/P399fbbb3uMtPr61wgbN26so0ePehyy7NKlS4m+biRmwIABypQpk5599tkEz+mzZ8/queeeU+bMmTVgwIC/rZWU29yqVSutXbtWS5YsSbDu3Llzunr16m31L0mbNm1S6dKlFRwcfNuXwT8TI7fA/zd9+vREjynau3dvjR07VqtWrVK1atXUtWtXlSpVSmfPntXmzZu1fPlynT17VtK1UYqQkBBNnTpVWbNmVWBgoKpVq6bChQurUqVK+uSTT9SvXz9VqVJFWbJk0SOPPKL27dvr008/1XPPPadVq1apZs2aio2N1a+//qpPP/1US5YsSdYvp0VGRurDDz+UdO2wPPG/ULZ37161bt1ao0aNuuXlS5Uqpbp166pSpUrKnj27Nm7c6D4kU7xKlSpJujba1rhxY6VPn16tW7f2qt+MGTNq8eLF6tixo6pVq6ZFixZp4cKFevHFF93z9oKDg/XEE0/o7bfflsvlUpEiRfTNN98kOvc5Kb29/PLLWrZsmWrVqqXnn39efn5+mjZtmmJiYhI97mhaEBQUpClTpqh9+/aqWLGiWrdurZw5c+rQoUNauHChatasqUmTJunSpUvq2LGjihUrpldeeUWSNGLECH399dfq3LmzfvnlF/cHhUqVKmn58uV68803lTdvXhUuXDjBYdKu16xZM82fP99j1HHOnDnKkSOHatSokehlHn30Ub333ntauHCh6tevr/z586tly5YqV66csmTJouXLl2vDhg164403JF2bqz1lyhQ98sgjKl++vDp37qw8efLo119/1Y4dO9zhavLkyapVq5bKli2rrl276t5779XJkye1du1aHTlyRFu3bk3S/ZszZ071799fY8aMUdOmTdWkSRNt2bJFixYt8um/z5999llNmjRJbdq0Ue/evZUnTx7NmTPH/aMQfzeaXqxYMc2aNUvt2rVT2bJlE/xC2R9//KGPPvrotn79Kym3ecCAAfrqq6/UtGlTderUSZUqVVJ0dLR++eUXff755zpw4MBt3U9XrlzR6tWr9fzzz//ttgCHAsM/Xvwhf252Onz4sJmZnTx50rp3724FChQwf39/Cw0NtQYNGti7777rUe/LL7+0UqVKmZ+fn8dhqc6fP29t27a1kJAQk+RxWLDLly/buHHjrHTp0hYQEGDZsmWzSpUq2YgRIywyMtK9naRbHg7pRvGHGYo/ZcmSxYoVK2ZPPfWULV26NNHL3HgosJdfftmqVq1qISEhlilTJitRooS98sordvnyZfc2V69etZ49e1rOnDnN5XK5D3MVf3if1157LcH13OxQYIGBgbZ3715r1KiRZc6c2XLnzm3Dhg2z2NhYj8ufPn3aWrRoYZkzZ7Zs2bLZs88+a9u3b09Q82a9xd+f1x8KzMxs8+bN1rhxY8uSJYtlzpzZ6tWrZz/++KPHNjc7fNzNDlF2o5sdCiyxx/bGx+Pv3HgosOt7a9y4sQUHB1vGjBmtSJEi1qlTJ9u4caOZ/e8QVzceZmnjxo3m5+dn//rXv9zLfv31V3vwwQctU6ZMCQ79lJjNmzebJPfh7k6ePGl+fn7Wvn37m17mwoULljlzZnvssccsJibGBgwYYOXKlbOsWbNaYGCglStXzt55550El1uzZo01bNjQvd3999+f4FBqe/futQ4dOlhoaKj5+/tbvnz5rGnTpvb555+7t0nKYxwbG2sjRoywPHnyWKZMmaxu3bq2ffv2BI/dzQ4Fltjh+jp27Jjg0IH79u2ziIgIy5Qpk+XMmdP+/e9/2xdffGGSbN26dTe9L6+3bds2a9OmjeXJk8f9OtamTRv75ZdfEmwbv5/GH4Lverd7m82uHY5u8ODBVrRoUcuQIYPdc889VqNGDXv99dfdryO3eq0wM1u0aJFJst27d9/W7cQ/m8vMh7PiAQBIRIMGDZQ3b97b+jEN3L7x48erb9++OnLkiMdRHpymefPmcrlcmj9/fkq3gjSAcAsAuOPWr1+v2rVra/fu3e4vJCFpLl686HE0gUuXLqlChQqKjY11f+nSiXbt2qWyZcvq559/vuWh3oB4hFsAANKAhx9+WAULFlT58uXdc+l37NihOXPmqG3btindHpBq8IUyAADSgMaNG+s///mP5syZo9jYWJUqVUoff/yxnnzyyZRuDUhVGLkFAACAY3CcWwAAADgG4RYAAACOwZxbXfu5z2PHjilr1qx39edPAQAAcHvMTH/99Zfy5s2rdOluPj5LuJV07NixNPmb8QAAAP80hw8fVv78+W+6nnArKWvWrJKu3Vlp8bfjAQAAnC4qKkoFChRw57abIdzqf7/JHRQURLgFAABIxf5uCilfKAMAAIBjEG4BAADgGCkabr/77js98sgjyps3r1wulxYsWHDTbZ977jm5XC6NHz/eY/nZs2fVrl07BQUFKSQkRF26dNH58+fvbOMAAABIlVI03EZHR6tcuXKaPHnyLbebP3++1q1bp7x58yZY165dO+3YsUPLli3TN998o++++07dunW7Uy0DAAAgFUvRL5Q9/PDDevjhh2+5zdGjR9WzZ08tWbJEERERHut27dqlxYsXa8OGDapcubIk6e2331aTJk30+uuvJxqGAQAA4Fypes5tXFyc2rdvrwEDBqh06dIJ1q9du1YhISHuYCtJ4eHhSpcundavX3/TujExMYqKivI4AQAAIO1L1eF23Lhx8vPzU69evRJdf+LECeXKlctjmZ+fn7Jnz64TJ07ctO6YMWMUHBzsPvEDDgAAAM6QasPtpk2bNGHCBM2cOdPnP4k7ePBgRUZGuk+HDx/2aX0AAACkjFQbbr///nudOnVKBQsWlJ+fn/z8/HTw4EH9+9//VlhYmCQpNDRUp06d8rjc1atXdfbsWYWGht60dkBAgPsHG/jhBgAAAOdItb9Q1r59e4WHh3ssa9y4sdq3b6/OnTtLkqpXr65z585p06ZNqlSpkiRp5cqViouLU7Vq1e56zwAAAEhZKRpuz58/rz17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4BiEWwAAADgG4RYAAACOQbgFAACAYxBuAQAA4BiEWwAAADiGV+F23759vu4DAAAASDavwm3RokVVr149ffjhh7p06ZKve3KLjY3VkCFDVLhwYWXKlElFihTRqFGjZGbubcxMQ4cOVZ48eZQpUyaFh4dr9+7dd6wnAAAApF5e/YjD5s2bNWPGDPXr1089evTQk08+qS5duqhq1ao+bW7cuHGaMmWKZs2apdKlS2vjxo3q3LmzgoOD1atXL0nSq6++qokTJ2rWrFkqXLiwhgwZosaNG2vnzp3KmDGjT/sBAOBu8MUP/Uj82A/+mbwauS1fvrwmTJigY8eOafr06Tp+/Lhq1aqlMmXK6M0339Tp06d90tyPP/6oZs2aKSIiQmFhYWrZsqUaNWqkn376SdK1Udvx48fr//7v/9SsWTPdf//9mj17to4dO6YFCxb4pAcAAACkHcn6Qpmfn58ef/xxffbZZxo3bpz27Nmj/v37q0CBAurQoYOOHz+erOZq1KihFStW6Pfff5ckbd26VWvWrNHDDz8sSdq/f79OnDih8PBw92WCg4NVrVo1rV279qZ1Y2JiFBUV5XECAABA2pescLtx40Y9//zzypMnj9588031799fe/fu1bJly3Ts2DE1a9YsWc0NGjRIrVu3VokSJeTv768KFSqoT58+ateunSTpxIkTkqTcuXN7XC537tzudYkZM2aMgoOD3acCBQokq08AAACkDl7NuX3zzTc1Y8YM/fbbb2rSpIlmz56tJk2aKF26a1m5cOHCmjlzpsLCwpLV3Keffqo5c+Zo7ty5Kl26tH7++Wf16dNHefPmVceOHb2uO3jwYPXr1899PioqioALAADgAF6F2ylTpujpp59Wp06dlCdPnkS3yZUrl95///1kNTdgwAD36K0klS1bVgcPHtSYMWPUsWNHhYaGSpJOnjzp0cfJkydVvnz5m9YNCAhQQEBAsnoDAABA6uNVuL2dQ21lyJAhWaOrknThwgX3aHC89OnTKy4uTtK1EeLQ0FCtWLHCHWajoqK0fv16/etf/0rWdQMAACDt8SrczpgxQ1myZNETTzzhsfyzzz7ThQsXkh1q4z3yyCN65ZVXVLBgQZUuXVpbtmzRm2++qaefflqS5HK51KdPH7388ssqVqyY+1BgefPmVfPmzX3SAwAAANIOr75QNmbMGN1zzz0JlufKlUujR49OdlPx3n77bbVs2VLPP/+8SpYsqf79++vZZ5/VqFGj3Nu88MIL6tmzp7p166YqVaro/PnzWrx4Mce4BQAA+AfyauT20KFDKly4cILlhQoV0qFDh5LdVLysWbNq/PjxGj9+/E23cblcGjlypEaOHOmz6wUAAEDa5NXIba5cubRt27YEy7du3aocOXIkuykAAADAG16F2zZt2qhXr15atWqVYmNjFRsbq5UrV6p3797uIxsAAAAAd5tX0xJGjRqlAwcOqEGDBvLzu1YiLi5OHTp08OmcWwAAACApvAq3GTJk0CeffKJRo0Zp69atypQpk8qWLatChQr5uj8AAADgtnkVbuMVL15cxYsX91UvAAAAQLJ4FW5jY2M1c+ZMrVixQqdOnXL/qEK8lStX+qQ5AAAAICm8Cre9e/fWzJkzFRERoTJlysjlcvm6LwDJFDZoYbJrHBgb4YNOAAC4e7wKtx9//LE+/fRTNWnSxNf9AAAAAF7z6lBgGTJkUNGiRX3dCwAAAJAsXoXbf//735owYYLMzNf9AAAAAF7zalrCmjVrtGrVKi1atEilS5eWv7+/x/p58+b5pDkAAAAgKbwKtyEhIXrsscd83QsAAACQLF6F2xkzZvi6DwAAACDZvJpzK0lXr17V8uXLNW3aNP3111+SpGPHjun8+fM+aw4AAABICq9Gbg8ePKiHHnpIhw4dUkxMjBo2bKisWbNq3LhxiomJ0dSpU33dJwAAAPC3vBq57d27typXrqw///xTmTJlci9/7LHHtGLFCp81BwAAACSFVyO333//vX788UdlyJDBY3lYWJiOHj3qk8YAAACApPJq5DYuLk6xsbEJlh85ckRZs2ZNdlMAAACAN7wKt40aNdL48ePd510ul86fP69hw4bxk7wAAABIMV5NS3jjjTfUuHFjlSpVSpcuXVLbtm21e/du3XPPPfroo4983SMAAABwW7wKt/nz59fWrVv18ccfa9u2bTp//ry6dOmidu3aeXzBDAAAALibvAq3kuTn56ennnrKl70AAAAAyeJVuJ09e/Yt13fo0MGrZgAAAIDk8Crc9u7d2+P8lStXdOHCBWXIkEGZM2cm3AIAACBFeHW0hD///NPjdP78ef3222+qVasWXygDAABAivEq3CamWLFiGjt2bIJRXQAAAOBu8Vm4la59yezYsWO+LAkAAADcNq/m3H711Vce581Mx48f16RJk1SzZk2fNAYAAAAklVfhtnnz5h7nXS6XcubMqfr16+uNN97wRV8AAABAknkVbuPi4nzdBwAAAJBsPp1zCwAAAKQkr0Zu+/Xrd9vbvvnmm95cBQAAAJBkXoXbLVu2aMuWLbpy5Yruu+8+SdLvv/+u9OnTq2LFiu7tXC6Xb7oEACAVChu00Cd1DoyN8EkdAF6G20ceeURZs2bVrFmzlC1bNknXftihc+fOql27tv7973/7tEkAAADgdng15/aNN97QmDFj3MFWkrJly6aXX36ZoyUAAAAgxXgVbqOionT69OkEy0+fPq2//vor2U0BAAAA3vAq3D722GPq3Lmz5s2bpyNHjujIkSP64osv1KVLFz3++OO+7hEAAAC4LV7NuZ06dar69++vtm3b6sqVK9cK+fmpS5cueu2113zaIAAAAHC7vAq3mTNn1jvvvKPXXntNe/fulSQVKVJEgYGBPm0OAAAASIpk/YjD8ePHdfz4cRUrVkyBgYEyM1/1BQAAACSZV+H2zJkzatCggYoXL64mTZro+PHjkqQuXbpwGDAAAACkGK/Cbd++feXv769Dhw4pc+bM7uVPPvmkFi9e7LPmAAAAgKTwas7t0qVLtWTJEuXPn99jebFixXTw4EGfNAYA8A1f/IoWv6AFIK3wauQ2OjraY8Q23tmzZxUQEJDspgAAAABveBVua9eurdmzZ7vPu1wuxcXF6dVXX1W9evV81hwAAACQFF5NS3j11VfVoEEDbdy4UZcvX9YLL7ygHTt26OzZs/rhhx983SMAAABwW7wauS1Tpox+//131apVS82aNVN0dLQef/xxbdmyRUWKFPF1jwAAAMBtSfLI7ZUrV/TQQw9p6tSpeumll+5ETwAAAIBXkjxy6+/vr23btt2JXgAAAIBk8WpawlNPPaX333/f170AAAAAyeLVF8quXr2q6dOna/ny5apUqZICAwM91r/55ps+aQ4AAABIiiSF23379iksLEzbt29XxYoVJUm///67xzYul8t33QEAAABJkKRwW6xYMR0/flyrVq2SdO3ndidOnKjcuXPfkeYAAACApEjSnFsz8zi/aNEiRUdH+7QhAAAAwFtefaEs3o1h9044evSonnrqKeXIkUOZMmVS2bJltXHjRo8ehg4dqjx58ihTpkwKDw/X7t2773hfAAAA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Je/DX2RkpOrWratVq1b5qj1JUkxMjD7//HOtXr3ap3U//vhjPfTQQ9q5c6cOHTrk09p3jSHVmD9/voWFhVnJkiUtU6ZM9vTTT9uxY8eSXGfhwoX2888/u89/8cUXVq1aNStSpIg1b97c3n///WT3+ttvv1nhwoXtnXfeSXateHFxcWZm9sknn1irVq2sevXqljlzZitatKgtXLgw2fU///xzCw4OttatW1uNGjWscuXK1q1bN69qXbhwwerXr2/PPPOMlSpVytq1a+ded/Xq1WT32r9/f2vRooXVqFHDsmfPbvfdd59X98GN+8K8efOsZs2aVrx4cRs+fLht3rw52b1GRkZauXLlrF27drZjx45k17vRzJkz7cEHH7SOHTvaxYsXvaqxcOFC27p1q5n9bz974okn7I033vBZn5s3b7aKFSvaM888Y9u3b/dZ3Xjz58+3LFmyWNGiRS0gIMCmTZtmUVFRya7p6/3hs88+sxw5clj58uUtXbp0Vr16dfvss8+SXXfgwIFWokQJu+eee6xOnTo+e+3p37+/PfbYY1alShULCQnx+rl2vd27d9vQoUNt8ODBZva/fS65vvnmG8uUKZO99957Xr033OjPP/+0atWqmcvlsn/961/u5bGxscmuHW/69OmWL18+69Wrl+3cudNndc3Mdu3aZYGBgTZz5kyf1bxw4YL77wcffNDq1KmT7JqXLl2yypUr24wZM5JdK178PrVx40YLCgqyL7/80id1P/vsM3O5XDZ//nxr27atDRs2zMx88752NxFuU4klS5ZYSEiITZs2zWJiYmzRokXmcrmsdevWdvjw4duuc+LECStcuLB17tzZ9u7dazt27LCsWbPayy+/bGPHjrXnn3/eMmTIYKNHj05Wv8uWLbPixYvbgQMH3Mt88QK+bt06y5w5s73//vv266+/2u7du61u3bpWvXp1++9//+t13Z07d1rBggVt6tSp7vOZMmVyv/l4Izo62szM3n//fbvvvvt8FnBnzJhhISEhtmnTJjt79qwdP37cGjVqZNWrV7dFixbddp3r94U9e/bYrl27LCQkxEaNGmW9e/e2ihUrWosWLez777/3utd4GzZssKpVq/o02F2/P82YMcPrgHv9/XB9+K5du7a9+eabPuk13p0IuHFxcXbmzBmrWbOmTZs2zXbv3m2jR482l8tlo0ePtnPnznlVd9OmTRYcHGwjR4702f6wefNmu+eee+w///mPnT171k6cOGEdO3a0Bx980ObNm+d13Y8++shCQ0NtwYIFNnPmTBswYID5+/vbmDFjvK5pZjZr1izLli2bbdq0yf744w87evSoNWzY0B544IEkPdeuFxkZaZUrV7acOXNa37593cuT+/p48eJFe+KJJ+zFF180s2uvP3v37rVXXnnF5s+f79UHncuXL1v9+vWtfPny1rBhQ/vwww/d63wZcGfNmmX33Xefde/e3WcBN76/Pn36WIsWLezMmTPJrrl48WJ76qmnbMmSJWZmdvDgQStatKiNHDnSq3rXv1Z16tTJ/R4RFxfns/s3MjLSWrVqZb179zaz5D1u8+bNM5fLZdOnTzczs6ZNm7o/9PjqA9rdQrhNBSIjI61bt242YsQIMzPbt2+fFSlSxFq2bGkhISHWrFkzO3jw4G3X27Rpk1WuXNm6d+9uL730kvXv39/juiZNmmQZM2a02bNne93z/PnzrUCBAu5we/0T6ttvv7VNmzZ5VXfatGlWqlQpj0/PR44csVq1alnRokXdLzpJtWTJEqtQoYKZXbt/CxUq5DFq622/ZmZ//fWXTZ8+3UqUKOGTgPvSSy9ZrVq1LDY21n2/HjlyxKpVq2ZFixZN0ptu/L7Qo0cPGzVqlI0aNcq97ptvvrF69epZ8+bNfRJw71Swi5ecgLtp0yarUqWKPfPMM/bLL7+YmVmjRo3cb+aXL182M/O4z73l6/vh4sWLduHCBXvxxRft7Nmz7uUTJkxwB9zIyMgk1dyzZ4+NGjXKXn75ZfcyX+wPc+bMsVKlSllkZKT7sTtx4oS1a9fOateubTExMUmuuWrVKnvmmWc8PohERUXZ22+/bYGBgckaFR46dKjVrFnTYmNj3f0eOXLEqlatmuTn2vU2b95sxYoVs/Lly7v/Y5BcFy5csMqVK1vPnj3tzJkz1qNHD6tTp47lz5/fcufO7fHcTopLly7Z8ePHLSIiwurVq+cRcM28ex3bu3evHT161GPZjBkzrESJEvavf/3Lfv/9d696/fbbb+2DDz7weI5+8cUXliNHDvc+6+3zNy4uzrp27Woul8uyZ89uw4YNs3379tkrr7xirVq1SvJ7xKJFi6xOnToWERFhY8eOtbp161rbtm3t4sWL7tcbb7z55pv2+uuvewx6vfvuuxYYGGh79uxx3xZv/Pe//7U5c+a4z/fs2dPat2/vsc3u3bu9qn23EW5TgZiYGPv0009tz549dubMGatQoYJ16dLFzK6NWLhcLmvSpIkdOXLktmtu2rTJqlataoUKFbLu3bt7rDt37px17tzZ2rZta5cvX/bqibBv3z7LlCmTexThen369LGhQ4d69QSePXu23XfffXbq1Ckz+1/o2LZtm2XJksXuv/9+r95wli5dak2aNLH9+/db/vz5rVu3bu4X7R9++MEGDhxohw4dSnLdeOfPn7fp06dbmTJl7NFHH/WqRvzjMHLkSKtcubI7wMXfBytXrrTMmTNbgwYNbMWKFbdd9/p9YeDAgR7rvv76a6tbt661bNnSVq5c6VXf17s+2PlqisL1++f06dPtwQcftE6dOtmlS5e86u3pp5+2X375xZ588slE78fz588nu2df3Q8LFiywxo0bW6lSpaxEiRIJgtKECRPM39/fhgwZctsBN35kMVeuXDZo0CCPdcndHz766CMrUqSIHT9+3MzMrly5YmZm+/fvN5fLZcuWLUtSvePHj1uRIkXc/3263tmzZ6158+bWq1cvM0vaG3r8tmPGjLHKlSu7P0zHP9eWL19umTJlsnr16tlXX32VpJ7jbd261e6//36fftibNWuWZcqUyYKCguyxxx6zWbNmmdm119x69eol64PZ3r17LSIiwho0aGAffPCBmV37oN21a9ck3bdnz561PHny2Isvvphg6sR//vMf8/f3t549e9q2bduS1F9MTIz16dPHXC6XPf744/baa6+513Xt2tVq1Khhf/31V5Jq3mj9+vXWpk0be+WVV6xy5cr23HPP2TPPPGMlS5a0t956y8xufz9bvXq1jRs3zlq3bm0tW7a0/Pnzm8vlskaNGlmZMmWse/fuNnDgwCR9kLxw4YINHDjQgoODrX79+vb000/bmTNn7OLFi9auXTt7/vnnkxWc48XfxldeecWqVavmfq8cNmyYVapUKckfplMC4TaViA8yH3zwgVWvXt39qeyjjz6yunXrWqFChZI0emt27cU1LCzMSpQoYVu2bPFY9+KLL1r58uWT9UR4//33zd/f3wYMGGC//PKL7dy501544QULCQmxXbt2eVVz9+7dljFjRhsyZIjH8o0bN1qdOnWsTZs2Sb4fzK69uWbOnNlcLpf7zTBer169rFGjRh6jYt44f/68vfPOO1a1atUEoxZJsW3bNkufPr0NHz7cY/nixYutRYsWVr9+fQsPD0/SY7d161YrXLiw1axZM8Eb7cKFC61ChQrWrl07jxFzb23evNmqVq1qrVu39no/uNH1byjxc3CHDh2a5DfzzZs3W+XKla1jx46WJUsWu/feey08PNwaNmxo9evXtzp16linTp1Sxf2wYcMGCwoKsueee846depk/v7+1rt3b4+pQGZmY8eOtWzZstkff/yRpN6KFy/u8/1hz549FhAQYP/3f//nsfzAgQNWtmxZW7duXZLqmV3bd4sUKWIVK1ZMMCe4S5cu9vDDDye5Zrzt27ebn59fgufawoULrXnz5vb4449b7dq1vZ6Deyc+7O3YscOWLl1qZv8bpezevbt16NAhyR/4brRv3z577LHHrEyZMlalShULCgry6jFbtWqVhYWF2YgRIxK8FlaqVMmCg4PthRde8Gokf+fOnfavf/3LSpQoYSVKlLDp06fbhAkT7NFHH/XqPw4rVqyw9957z8yu3Z89evSwp59+2qKiouydd96xZ555xlwul7lcLq/ui3jLly+3kJAQe/3112348OHWqVMnK126tHu0NSkOHz5s7777rlWsWNFKlChhHTp0sIiICIuIiHAH/ORMI4i/7KRJk+y+++4zM7Phw4ebv7+/bdy40eu6dxPhNpUZOXKklSlTxh20Bg0aZG+//bbXIXTbtm1WtmxZ69Spk8cXi7p162bh4eHJGqWKjY21Tz/91LJly2b58+e3okWL2n333ZfsL6V88MEH5u/vby+++KLt37/f/vzzTxsyZIh17NgxWZ8YFyxYYIGBgTZw4ED7/fff7ZdffrH+/ftbSEiI+1/VyRUdHe31HMjrzZgxw/3BYePGje5RlVdeecV27tzp1SjY1q1brXz58tatW7cEgWbJkiUJQlNy/PTTT1anTh2ffOkl3vUv1v3797datWp59ea4adMmK1u2rJUrV87atm1rs2bNsgkTJtiwYcNszJgxPv0ymLf3w549e2zo0KEec0rfeecdy58/vw0aNCjBY+XNB7M7tT98+OGHliFDBhs0aJDt3r3bTp48aS+99JIVKFDA6w99W7dutXLlylmHDh3cH9SjoqKsRo0a1rVrV69qxot/rvXv399++ukn27Nnj0VERNiQIUPs2LFj1qpVKytbtqzXU6Lu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", + "text/plain": [ + "<Figure size 800x600 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Put your code here\n" + ] + }, + { + "cell_type": "markdown", + "id": "03674516-86f8-42a3-83e3-5ecb1c376a30", + "metadata": {}, + "source": [ + "<img src=\"340px-English-slf.png\" alt=\"Letter Frequencies English\" width=\"500\" height=\"auto\">\n", + "This should look roughly similar, as we are using an English text.\n", + "\n", + "Now we use our cypher using a random key. Can you figure out the correct key from the frequency analysis of the cypher text and the standard English letter distribution? Try out your guess by decoding the cypher text!" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "8ae904cd", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAArcAAAIpCAYAAAC48RBEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8WgzjOAAAACXBIWXMAAA9hAAAPYQGoP6dpAABZ+ElEQVR4nO3deXhMd///8deQBSEJitijllprp7baghYtLVVLbVXau3Y3RXvbW0tXlKK9a2vpji5uO9VqUVuppa1930olFQTJ+/eHX+ZrJFQmQ5LT5+O65roy55x5z3tmzsy85pPPnHGZmQkAAABwgHQp3QAAAADgK4RbAAAAOAbhFgAAAI5BuAUAAIBjEG4BAADgGIRbAAAAOAbhFgAAAI5BuAUAAIBjEG4BAADgGIRbAB7Cw8PVqVOnO349Bw4ckMvl0syZM93LOnXqpMyZM9/x647ncrk0fPjwu3Z98YYPHy6Xy3XXrzcl/fTTTwoICNDBgwdTupW75sbn0rfffiuXy6Vvv/02xXq60+7E68fOnTvl5+en7du3+7QunItwi3+8mTNnyuVyaePGjcmudezYMQ0fPlw///xzgnVz587V+PHjk30dSVGnTh25XC65XC6lS5dOwcHBuu+++9S+fXstW7bMZ9fzv//9L0VC4u1Izb35wvWP8a1OvrwPRo8erQULFiTpMi+99JLatGmjggULJrq+SpUqcrlcmjJlig86xM3s2LFDTz31lPLmzavAwEDlyZNH7dq1044dO1K6tZsqWbKkmjRpoqFDh6Z0K0gjXGZmKd0EkJJmzpypzp07a8OGDapUqVKyam3cuFGVK1fWjBkzEoxeNG3aVNu3b9eBAweSdR1JUadOHe3du1djxoyRJEVHR2vPnj2aN2+e9u3bp1atWunDDz+Uv7+/+zIxMTFKly6dx7K/06NHD02ePFlJeTkxM8XExMjf31/p06eXdG3k9vPPP9f58+dvu05yert06ZL8/Pzk5+fns+u7HVevXtXVq1eVIUOGZNdatmyZTp486T6/YcMGTZw4US+++KJKlCjhXn7//ffr/vvvT/b1SVLmzJnVsmVLj1H3W/n5559Vvnx5/fjjj6pWrVqC9bt371axYsUUHh6uvHnzas2aNT7pM6WFh4erTp067vspLi5Oly9fVkBAgNKlu/tjS/PmzVObNm2ULVs2denSRYUKFdKBAwf0/vvv68yZM/r444/12GOPJes6brzNvrJo0SI1btxYe/bsUeHChX1aG85zd1/RAfhU/JvlrUJSSEiInnrqKY9lY8eOVa9evfTOO+8oPDxc48aNc68LDAy8Y/1K14JdXFycAgICfBLukiOlrt+XgbpBgwYe5zNkyKCJEyeqQYMGqlOnjk+uI7lmzJihAgUK6IEHHkh0/YcffqicOXPqjTfeUMuWLXXgwAGFh4ff3SbvgnTp0qXYPrd37161b99e9957r7777jvlyJHDva53796qVauW2rdvr23btunee++9aZ3o6GgFBQXdjZY9XisiIiKUNWtWzZo1SyNHjrwr14+0i2kJwG06evSonn76aeXKlUuBgYEqVaqUpk+f7l7/7bffqnLlypKkzp07u/8dPHPmTNWpU0cLFy7UwYMH3cuvf/OOiYnRsGHDVKRIEQUGBip//vx64YUXFBMT49GDy+VSjx49NGfOHJUqVUqBgYFavHhxkm9L+vTpNXHiRJUsWVKTJk1SZGSke92Nc+auXLmiESNGqGjRosqQIYOyZ8+umjVruqc1dOrUSZMnT3b3F3+S/m9e7euvv67x48ercOHCCgwM1M6dOxOdcxtv3759atSokYKCgpQnTx6NHDnSY+T1ZnMXb6x5q97il9347/otW7bo4YcfVnBwsDJnzqz69etr3bp1HtvET2X54Ycf1K9fP+XIkUNBQUF67LHHdPr06b+9/xObcxv/2C5YsEClS5d272PePL6JWbRokWrVqqWgoCBlyZJFTZo08fhX9MqVK5UuXboE//qdO3eux3QBl8ul6OhozZo1y31//t0cywULFqhevXo3nWc8d+5ctWzZUk2bNlVISIjmzp2bYJu//vpLffr0UXh4uAIDA5UzZ041aNBAmzdv9thu/fr1aty4sbJmzaqgoCDdf//9mjBhgsc2v/76q1q2bKls2bIpQ4YMqlSpkr766iuPbZLyGJuZXn75ZeXLl0+ZMmVS3bp1E/03f2L7bZ06dVS6dGnt3LlTdevWVaZMmZQ3b169+uqrCS5/8OBBPfroowoKClLOnDnVt29fLVmy5Lbm8b722mu6cOGC3n33XY9gK0n33HOPpk2bpujoaI/rjd9Pd+7cqbZt2ypr1qyqWbNmkm6zJJ07d059+vRR/vz5FRgYqCJFimjcuHGKi4tzb3Or1wpJ8vf3V506dfTll1/e8nYCEiO3wG05efKkHnjgAXcAyZEjhxYtWqQuXbooKipKffr0UYkSJTRy5EgNHTpU3bp1U61atSRJ1atXV968eRUZGakjR47orbfekiT3F6fi4uL06KOPas2aNerWrZtKlCihX375RW+99ZZ+//33BHMbV65cqU8//VQ9evTQPffc4/UIV/r06dWmTRsNGTJEa9asUZMmTRLdbvjw4RozZoyeeeYZValSRVFRUdq4caM2b96sBg0a6Nlnn9WxY8e0bNkyffDBB4nWmDFjhi5duqRu3bopMDBQ2bJl83hju15sbKweeughPfDAA3r11Ve1ePFiDRs2TFevXk3yiM3t9Ha9HTt2qFatWgoODtYLL7wgf39/TZs2TXXq1NHq1atVtWpVj+179uyprFmzatiwYTpw4IDGjx+vHj166JNPPklSn/HWrFmjefPm6fnnn1eWLFk0ceJEtWjRQocOHVL27Nm9qilJH3zwgTp27KhGjRpp3LhxunDhgqZMmaKaNWtqy5YtCg8PV7169fT8889rzJgxat68uSpUqKDjx4+rZ8+eioiI0HPPPeeuFb8vdOvWTZJu+W/io0eP6tChQ6pQoUKi69evX689e/ZoxowZCggI0OOPP645c+boxRdf9Njuueee0+eff64ePXqoZMmSOnPmjNasWaNdu3a5ay9btkxNmzZV7ty51bt3b4WFhWnXrl365ptv1Lt3b0nXHuMaNWoob968GjRokIKCgvTpp5+qefPm+uKLLxL8W/52HuOhQ4fq5ZdfVuPGjdW4cWNt3rxZDRs21OXLl2/r8fnzzz/10EMP6fHHH1erVq30+eefa+DAgSpTpowefvhhSddGTOvVq6fjx4+7b9vcuXO1atWq27qOr7/+WuHh4e7XpRs9+OCDCg8P18KFCxOse+KJJ1S0aFGNHj3a/SHzdm/zhQsXVLt2bR09elTPPvusChQooB9//FGDBw/W8ePHE3wPIbHXingVK1bUl19+qaioKAUHB9/W7cY/lAH/cDNmzDBJtmHDhptu06VLF8udO7f98ccfHstbt25tISEhduHCBTMz27Bhg0myGTNmJKjRpEkTK1iwYILlH3zwgaVLl86+//57j+VTp041SfbDDz+4l0mydOnS2Y4dO27rttWuXdtKlSp10/Xz5883STZhwgT3soIFC1rHjh3d58uWLWtNmjS55fV0797dEns52b9/v0my4OBgO3XqVKLrrr+vOnbsaJKsZ8+e7mVxcXHWpEkTCwgIsNOnT5uZ2apVq0ySrVq16m9r3qw3s2v357Bhw9znmzdvbgEBAbZ37173smPHjlmWLFnswQcfdC+L32ciIiIsLi7Ovbxv376WPn16O3fuXKLXF2/YsGEJepJkAQEBtmfPHveyrVu3miR7++23b1nvep999pnHffPXX39ZaGiode3a1WO7EydOWEhIiMfy6OhoK1KkiJUqVcouXbpkTZo0seDgYDt48KDHZYOCgjz2kVtZvny5SbKvv/460fU9evSw/Pnzu+/HpUuXmiTbsmWLx3YhISHWvXv3m17P1atXrVChQlawYEH7888/PdZd/xjVr1/fypQpY5cuXfJYX716dStatKh72e0+xqdOnbKAgABr0qSJx3YvvviiSfK4nxLbb2vXrm2SbPbs2e5lMTExFhYWZi1atHAve+ONN0ySLViwwL3s4sWLVrx48USfC9c7d+6cSbJmzZrddBszs0cffdQkWVRUlJn9337apk0bj+2ScptHjRplQUFB9vvvv3vUGDRokKVPn94OHTpkZrd+rYg3d+5ck2Tr16+/5e0AmJYA/A0z0xdffKFHHnlEZqY//vjDfWrUqJEiIyMT/Gs0KT777DOVKFFCxYsX96hdr149SUowMlO7dm2VLFkyWbcpXvzo8V9//XXTbUJDQ7Vjxw7t3r3b6+tp0aJFgn+F3kqPHj3cf8ePll++fFnLly/3uoe/Exsbq6VLl6p58+Yecw5z586ttm3bas2aNYqKivK4TLdu3Tz+1V6rVi3FxsZ6fbiriIgIj1HQ+++/X8HBwdq3b59X9aRro5nnzp1TmzZtPPav9OnTq2rVqh77V6ZMmTRz5kzt2rVLDz74oBYuXKi33npLBQoU8Pr6z5w5I0nKmjVrgnVXr17VJ598oieffNJ9P9arV085c+bUnDlzPLYNDQ3V+vXrdezYsUSvZ8uWLdq/f7/69Omj0NBQj3Xxtc+ePauVK1eqVatW+uuvv9z3xZkzZ9SoUSPt3r1bR48e9bjs3z3Gy5cv1+XLl9WzZ0+P7fr06XMb9841mTNn9pgXHxAQoCpVqng87osXL1bevHn16KOPupdlyJBBXbt2/dv68c/vLFmy3HK7+PU37ufxo/bxknKbP/vsM9WqVUtZs2b12P8iIiIUGxur7777zmP7W71WxO9Df/zxxy1vB8C0BOBvnD59WufOndO7776rd999N9FtTp065XX93bt3a9euXTd9Qb+xdqFChby+rhvFH5XgVm96I0eOVLNmzVSsWDGVLl1aDz30kNq3b5+kb94nped06dIl+EJLsWLFJOmOHmni9OnTunDhgu67774E60qUKKG4uDgdPnxYpUqVci+/MfTFv/n++eefXvWQWIjMmjWr1/UkuT+UxH9YutGN/96tUaOG/vWvf2ny5Mlq1KiRnn76aa+v+3qWyNEqli5dqtOnT6tKlSras2ePe3ndunX10Ucfady4ce6jCrz66qvq2LGj8ufPr4oVK6px48bq0KGDe1/Zu3evJKl06dI37WHPnj0yMw0ZMkRDhgxJdJtTp04pb9687vN/9xjHh9yiRYt6bJcjR45EA31i8uXLl2A+ctasWbVt2zb3+YMHD6pw4cIJtitSpMjf1o9/ft/qQ+z16298Pbjx+ZuU27x7925t27bNJ69v8fvQP+0Y0Ug6wi3wN+Lnhj711FPq2LFjotsk5xBLcXFxKlOmjN58881E1+fPn9/jfMaMGb2+rhvFHxT9Vm+QDz74oPbu3asvv/xSS5cu1X//+1+99dZbmjp1qp555pnbuh5f9izd/M0tNjbWp9fzd+IPYXajxIJcStST/m///eCDDxQWFpZg/Y1HbYiJiXF/OWnv3r26cOGCMmXK5PX1x88VTiygx4/OtmrVKtHLrl69WnXr1nVvU6tWLc2fP19Lly7Va6+9pnHjxmnevHnueal/J/6+6N+/vxo1apToNjc+F+7EY3KjO30dISEhyp07t0dYTsy2bduUN2/eBB94kvP8jYuLU4MGDfTCCy8kuj7+g+vtXFf8PnTPPfd43Q/+GQi3wN/IkSOHsmTJotjYWEVERNxy21uNKNxsXeHChbV161bVr1//ro5IxMbGau7cucqUKZP7G9A3ky1bNnXu3FmdO3fW+fPn9eCDD2r48OHucOvLvuPi4rRv3z6PN73ff/9dktxfnosfHTp37pzHZRObDnC7veXIkUOZMmXSb7/9lmDdr7/+qnTp0iX4oJEWxE9zyJkz59/uv5I0bNgw7dq1S6+//roGDhyoQYMGaeLEiR7bJOXxLl68uCRp//79Hsujo6P15Zdf6sknn1TLli0TXK5Xr16aM2eOO9xK16aIPP/883r++ed16tQpVahQQa+88ooefvhh9+3cvn37TW9n/Civv7//bd0XtyP+Ryl2797t8R+H06dPJ2vEPbHr2blzp8zM4/6/fsT7Vpo2bar33ntPa9asSfT5/v333+vAgQN69tlnb6sX6fZuc+HChXX+/Hmf3N/79+9XunTpEgRi4EbMuQX+Rvr06dWiRQt98cUXif784/WHBYo//uONoSt+3fWH3IrXqlUrHT16VO+9916CdRcvXlR0dHQyuk9cbGysevXqpV27dqlXr163/OZx/JzJeJkzZ1aRIkU8DlN2q9vtjUmTJrn/NjNNmjRJ/v7+ql+/vqRrb67p06dPMF/vnXfeSVDrdntLnz69GjZsqC+//NJj+sPJkyc1d+5c1axZM01+Q7tRo0YKDg7W6NGjdeXKlQTrr99/169fr9dff119+vTRv//9bw0YMECTJk3S6tWrPS4TFBR024913rx5lT9//gS/ADh//nxFR0ere/fuatmyZYJT06ZN9cUXXygmJkaxsbEJnjs5c+ZUnjx53PthhQoVVKhQIY0fPz5Bb/EjoDlz5lSdOnU0bdo0HT9+/Jb3xe2KiIiQv7+/3n77bY+RVl//GmGjRo109OhRj0OWXbp0KdHXjcQMGDBAGTNm1LPPPpvgOX327Fk999xzypQpkwYMGPC3tZJym1u1aqW1a9dqyZIlCdadO3dOV69eva3+JWnTpk0qVaqUQkJCbvsy+Gdi5Bb4/6ZPn57oMUV79+6tsWPHatWqVapataq6du2qkiVL6uzZs9q8ebOWL1+us2fPSro2ShEaGqqpU6cqS5YsCgoKUtWqVVWoUCFVrFhRn3zyifr166fKlSsrc+bMeuSRR9S+fXt9+umneu6557Rq1SrVqFFDsbGx+vXXX/Xpp59qyZIlyfrltMjISH344YeSrh2WJ/4Xyvbu3avWrVtr1KhRt7x8yZIlVadOHVWsWFHZsmXTxo0b3YdkilexYkVJ10bbGjVqpPTp06t169Ze9ZshQwYtXrxYHTt2VNWqVbVo0SItXLhQL774onveXkhIiJ544gm9/fbbcrlcKly4sL755ptE5z4npbeXX35Zy5YtU82aNfX888/Lz89P06ZNU0xMTKLHHU0LgoODNWXKFLVv314VKlRQ69atlSNHDh06dEgLFy5UjRo1NGnSJF26dEkdO3ZU0aJF9corr0iSRowYoa+//lqdO3fWL7/84v6gULFiRS1fvlxvvvmm8uTJo0KFCiU4TNr1mjVrpvnz53uMOs6ZM0fZs2dX9erVE73Mo48+qvfee08LFy5UvXr1lC9fPrVs2VJly5ZV5syZtXz5cm3YsEFvvPGGpGtztadMmaJHHnlE5cqVU+fOnZU7d279+uuv2rFjhztcTZ48WTVr1lSZMmXUtWtX3XvvvTp58qTWrl2rI0eOaOvWrUm6f3PkyKH+/ftrzJgxatq0qRo3bqwtW7Zo0aJFPv33+bPPPqtJkyapTZs26t27t3Lnzq05c+a4fxTi70bTixYtqlmzZqldu3YqU6ZMgl8o++OPP/TRRx/d1q9/JeU2DxgwQF999ZWaNm2qTp06qWLFioqOjtYvv/yizz//XAcOHLit++nKlStavXq1nn/++b/dFuBQYPjHiz/kz81Ohw8fNjOzkydPWvfu3S1//vzm7+9vYWFhVr9+fXv33Xc96n355ZdWsmRJ8/Pz8zgs1fnz561t27YWGhpqkjwOC3b58mUbN26clSpVygIDAy1r1qxWsWJFGzFihEVGRrq3k3TLwyHdKP4wQ/GnzJkzW9GiRe2pp56ypUuXJnqZGw8F9vLLL1uVKlUsNDTUMmbMaMWLF7dXXnnFLl++7N7m6tWr1rNnT8uRI4e5XC73Ya7iD+/z2muvJbiemx0KLCgoyPbu3WsNGza0TJkyWa5cuWzYsGEWGxvrcfnTp09bixYtLFOmTJY1a1Z79tlnbfv27Qlq3qy3+Pvz+kOBmZlt3rzZGjVqZJkzZ7ZMmTJZ3bp17ccff/TY5maHj7vZIcpudLNDgSX22N74ePydGw8Fdn1vjRo1spCQEMuQIYMVLlzYOnXqZBs3bjSz/zvE1Y2HWdq4caP5+fnZv/71L/eyX3/91R588EHLmDFjgkM/JWbz5s0myX24u5MnT5qfn5+1b9/+ppe5cOGCZcqUyR577DGLiYmxAQMGWNmyZS1LliwWFBRkZcuWtXfeeSfB5dasWWMNGjRwb3f//fcnOJTa3r17rUOHDhYWFmb+/v6WN29ea9q0qX3++efubZLyGMfGxtqIESMsd+7cljFjRqtTp45t3749wWN3s0OBJXa4vo4dOyY4dOC+ffusSZMmljFjRsuRI4f9+9//ti+++MIk2bp16256X15v27Zt1qZNG8udO7f7daxNmzb2yy+/JNg2fj+NPwTf9W73NptdOxzd4MGDrUiRIhYQEGD33HOPVa9e3V5//XX368itXivMzBYtWmSSbPfu3bd1O/HP5jLz4ax4AAASUb9+feXJk+e2fkwDt2/8+PHq27evjhw54nGUB6dp3ry5XC6X5s+fn9KtIA0g3AIA7rj169erVq1a2r17t/sLSUiaixcvehxN4NKlSypfvrxiY2PdX7p0ol27dqlMmTL6+eefb3moNyAe4RYAgDTg4YcfVoECBVSuXDn3XPodO3Zozpw5atu2bUq3B6QafKEMAIA0oFGjRvrvf/+rOXPmKDY2ViVLltTHH3+sJ598MqVbA1IVRm4BAADgGBznFgAAAI5BuAUAAIBjMOdW137u89ixY8qSJctd/flTAAAA3B4z019//aU8efIoXbqbj88SbiUdO3YsTf5mPAAAwD/N4cOHlS9fvpuuJ9xKypIli6Rrd1Za/O14AAAAp4uKilL+/Pndue1mCLf6v9/kDg4OJtwCAACkYn83hZQvlAEAAMAxCLcAAABwjBQNt999950eeeQR5cmTRy6XSwsWLLjpts8995xcLpfGjx/vsfzs2bNq166dgoODFRoaqi5duuj8+fN3tnEAAACkSikabqOjo1W2bFlNnjz5ltvNnz9f69atU548eRKsa9eunXbs2KFly5bpm2++0Xfffadu3brdqZYBAACQiqXoF8oefvhhPfzww7fc5ujRo+rZs6eWLFmiJk2aeKzbtWuXFi9erA0bNqhSpUqSpLfffluNGzfW66+/nmgYBgAAgHOl6jm3cXFxat++vQYMGKBSpUolWL927VqFhoa6g60kRUREKF26dFq/fv1N68bExCgqKsrjBAAAgLQvVYfbcePGyc/PT7169Up0/YkTJ5QzZ06PZX5+fsqWLZtOnDhx07pjxoxRSEiI+8QPOAAAADhDqg23mzZt0oQJEzRz5kyf/yTu4MGDFRkZ6T4dPnzYp/UBAACQMlJtuP3+++916tQpFShQQH5+fvLz89PBgwf173//W+Hh4ZKksLAwnTp1yuNyV69e1dmzZxUWFnbT2oGBge4fbOCHGwAAAJwj1f5CWfv27RUREeGxrFGjRmrfvr06d+4sSapWrZrOnTunTZs2qWLFipKklStXKi4uTlWrVr3rPQMAACBlpWi4PX/+vPbs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99q7d6+k5H34i4yMVJ06dbRq1SpftSdJiomJ0eeff67Vq1f7tO7HH3+shx56SDt37tShQ4d8WvuuMaQa8+fPt/DwcCtRooRlzJjRnn76aTt27FiS6yxcuNB+/vln9/kvvvjCqlataoULF7bmzZvb+++/n+xef/vtNytUqJC98847ya4VLy4uzszMPvnkE2vVqpVVq1bNMmXKZEWKFLGFCxcmu/7nn39uISEh1rp1a6tevbpVqlTJunXr5lWtCxcuWL169eyZZ56xkiVLWrt27dzrrl69muxe+/fvby1atLDq1atbtmzZ7L777vPqPrhxX5g3b57VqFHDihUrZsOHD7fNmzcnu9fIyEgrW7astWvXznbs2JHsejeaOXOmPfjgg9axY0e7ePGiVzUWLlxoW7duNbP/28+eeOIJe+ONN3zW5+bNm61ChQr2zDPP2Pbt231WN978+fMtc+bMVqRIEQsMDLRp06ZZVFRUsmv6en/47LPPLHv27FauXDlLly6dVatWzT777LNk1x04cKAVL17c7rnnHqtdu7bPXnv69+9vjz32mFWuXNlCQ0O9fq5db/fu3TZ06FAbPHiwmf3fPpdc33zzjWXMmNHee+89r94bbvTnn39a1apVzeVy2b/+9S/38tjY2GTXjjd9+nTLmzev9erVy3bu3OmzumZmu3btsqCgIJs5c6bPal64cMH994MPPmi1a9dOds1Lly5ZpUqVbMaMGcmuFS9+n9q4caMFBwfbl19+6ZO6n332mblcLps/f761bdvWhg0bZma+eV+7mwi3qcSSJUssNDTUpk2bZjExMbZo0SJzuVzWunVrO3z48G3XOXHihBUqVMg6d+5se/futR07dliWLFns5ZdftrFjx9rzzz9vAQEBNnr06GT1u2zZMitWrJgdOHDAvcwXL+Dr1q2zTJky2fvvv2+//vqr7d692+rUqWPVqlWz//3vf17X3blzpxUoUMCmTp3qPp8xY0b3m483oqOjzczs/ffft/vuu89nAXfGjBkWGhpqmzZtsrNnz9rx48etYcOGVq1aNVu0aNFt17l+X9izZ4/t2rXLQkNDbdSoUda7d2+rUKGCtWjRwr7//nuve423YcMGq1Klik+D3fX704wZM7wOuNffD9eH71q1atmbb77pk17j3YmAGxcXZ2fOnLEaNWrYtGnTbPfu3TZ69GhzuVw2evRoO3funFd1N23aZCEhITZy5Eif7Q+bN2+2e+65x/773//a2bNn7cSJE9axY0d78MEHbd68eV7X/eijjywsLMwWLFhgM2fOtAEDBpi/v7+NGTPG65pmZrNmzbKsWbPapk2b7I8//rCjR49agwYN7IEHHkjSc+16kZGRVqlSJcuRI4f17dvXvTy5r48XL160J554wl588UUzu/b6s3fvXnvllVds/vz5Xn3QuXz5stWrV8/KlStnDRo0sA8//NC9zpcBd9asWXbfffdZ9+7dfRZw4/vr06ePtWjRws6cOZPsmosXL7annnrKlixZYmZmBw8etCJFitjIkSO9qnf9a1WnTp3c7xFxcXE+u38jIyOtVatW1rt3bzNL3uM2b948c7lcNn36dDMza9q0qftDj68+oN0thNtUIDIy0rp162YjRowwM7N9+/ZZ4cKFrWXLlhYaGmrNmjWzgwcP3na9TZs2WaVKlax79+720ksvWf/+/T2ua9KkSZYhQwabPXu21z3Pnz/f8ufP7w631z+hvv32W9u0aZNXdadNm2YlS5b0+PR85MgRq1mzphUpUsT9opNUS5YssfLly5vZtfu3YMGCHqO23vZrZvbXX3/Z9OnTrXjx4j4JuC+99JLVrFnTYmNj3ffrkSNHrGrVqlakSJEkvenG7ws9evSwUaNG2ahRo9zrvvnmG6tbt641b97cJwH3TgW7eMkJuJs2bbLKlSvbM888Y7/88ouZmTVs2ND9Zn758mUzM4/73Fu+vh8uXrxoFy5csBdffNHOnj3rXj5hwgR3wI2MjExSzT179tioUaPs5Zdfdi/zxf4wZ84cK1mypEVGRrofuxMnTli7du2sVq1aFhMTk+Saq1atsmeeecbjg0hUVJS9/fbbFhQUlKxR4aFDh1qNGjUsNjbW3e+RI0esSpUqSX6uXW/z5s1WtGhRK1eunPs/Bsl14cIFq1SpkvXs2dPOnDljPXr0sNq1a1u+fPksV65cHs/tpLh06ZIdP37cmjRpYnXr1vUIuGbevY7t3bvXjh496rFsxowZVrx4cfvXv/5lv//+u1e9fvvtt/bBBx94PEe/+OILy549u3uf9fb5GxcXZ127djWXy2XZsmWzYcOG2b59++yVV16xVq1aJfk9YtGiRVa7dm1r0qSJjR071urUqWNt27a1ixcvul9vvPHmm2/a66+/7jHo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", + "text/plain": [ + "<Figure size 800x600 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mh ux, hk ghm mh ux, matm bl max jnxlmbhg:\n", + "Paxmaxk 'mbl ghuexk bg max fbgw mh lnyyxk\n", + "Max lebgzl tgw tkkhpl hy hnmktzxhnl yhkmngx,\n", + "Hk mh mtdx tkfl tztbglm t lxt hy mkhnuexl\n", + "Tgw ur hiihlbgz xgw maxf. Mh wbx--mh lexxi,\n", + "Gh fhkx; tgw ur t lexxi mh ltr px xgw\n", + "Max axtkm-tvax tgw max mahnltgw gtmnkte lahvdl\n", + "Matm yexla bl axbk mh: 'mbl t vhglnfftmbhg\n", + "Wxohnmer mh ux pbla'w. Mh wbx, mh lexxi;\n", + "Mh lexxi, ixkvatgvx mh wkxtf--tr, maxkx'l max knu:\n", + "Yhk bg matm lexxi hy wxtma patm wkxtfl ftr vhfx,\n", + "Paxg px atox lanyyexw hyy mabl fhkmte vhbe,\n", + "Fnlm zbox nl itnlx--maxkx'l max kxlixvm\n", + "Matm ftdxl vtetfbmr hy lh ehgz ebyx.\n", + "Yhk pah phnew uxtk max pabil tgw lvhkgl hy mbfx,\n", + "Ma'hiikxllhk'l pkhgz, max ikhnw ftg'l vhgmnfxer,\n", + "Max itgzl hy wblikbs'w ehox, max etp'l wxetr,\n", + "Max bglhexgvx hy hyybvx, tgw max linkgl\n", + "Matm itmbxgm fxkbm hy ma'ngphkmar mtdxl,\n", + "Paxg ax abflxey fbzam abl jnbxmnl ftdx\n", + "Pbma t utkx uhwdbg? Pah phnew ytkwxel uxtk,\n", + "Mh zkngm tgw lpxtm ngwxk t pxtkr ebyx,\n", + "Unm matm max wkxtw hy lhfxmabgz tymxk wxtma,\n", + "Max ngwblvhoxkx'w vhngmkr, ykhf pahlx uhnkg\n", + "Gh mktoxeexk kxmnkgl, inssexl max pbee,\n", + "Tgw ftdxl nl ktmaxk uxtk mahlx beel px atox\n", + "Matg yer mh hmaxkl matm px dghp ghm hy?\n", + "Manl vhglvbxgvx whma ftdx vhptkwl hy nl tee,\n", + "Tgw manl max gtmbox anx hy kxlhenmbhg\n", + "Bl lbvdebxw h'xk pbma max itex vtlm hy mahnzam,\n", + "Tgw xgmxkikblxl hy zkxtm ibma tgw fhfxgm\n", + "Pbma mabl kxztkw maxbk vnkkxgml mnkg tpkr\n", + "Tgw ehlx max gtfx hy tvmbhg.\n" + ] + } + ], + "source": [ + "cypher_text = encode_message(original_text, random.randint(1,25)) # If you re=run this cell, the key will change!\n", + "plot_frequencies(count_letters(cypher_text))\n", + "print(cypher_text)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "3ed45915-a7cf-4d93-9d95-cdb591a45771", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Decoded Message:\n", + " To be, or not to be, that is the question:\n", + "Whether 'tis nobler in the mind to suffer\n", + "The slings and arrows of outrageous fortune,\n", + "Or to take arms against a sea of troubles\n", + "And by opposing end them. To die--to sleep,\n", + "No more; and by a sleep to say we end\n", + "The heart-ache and the thousand natural shocks\n", + "That flesh is heir to: 'tis a consummation\n", + "Devoutly to be wish'd. To die, to sleep;\n", + "To sleep, perchance to dream--ay, there's the rub:\n", + "For in that sleep of death what dreams may come,\n", + "When we have shuffled off this mortal coil,\n", + "Must give us pause--there's the respect\n", + "That makes calamity of so long life.\n", + "For who would bear the whips and scorns of time,\n", + "Th'oppressor's wrong, the proud man's contumely,\n", + "The pangs of dispriz'd love, the law's delay,\n", + "The insolence of office, and the spurns\n", + "That patient merit of th'unworthy takes,\n", + "When he himself might his quietus make\n", + "With a bare bodkin? Who would fardels bear,\n", + "To grunt and sweat under a weary life,\n", + "But that the dread of something after death,\n", + "The undiscovere'd country, from whose bourn\n", + "No traveller returns, puzzles the will,\n", + "And makes us rather bear those ills we have\n", + "Than fly to others that we know not of?\n", + "Thus conscience doth make cowards of us all,\n", + "And thus the native hue of resolution\n", + "Is sicklied o'er with the pale cast of thought,\n", + "And enterprises of great pith and moment\n", + "With this regard their currents turn awry\n", + "And lose the name of action.\n" + ] + } + ], + "source": [ + "# Decoding\n", + "guessed_key = 19 # Put your guess here\n", + "decoded_text = decode_message(cypher_text, guessed_key)\n", + "print(\"Decoded Message:\\n\", decoded_text)" + ] + }, + { + "cell_type": "markdown", + "id": "2bd70c5e", + "metadata": {}, + "source": [ + "## Conclusion and final thoughts\n", + "Did the last cell yield an understandable English text? If yes: Congratulations! You cracked the code.\n", + "\n", + "Let's have a few closing questions:\n", + "- The presented method of frequency analysis above has some advantages but also some disadvantages. Can you name some?\n", + "- As stated above, this cypher is not used in reality, because it is very easily broken by brute force alone. However, increasing the key space does not solve this problem on its own, as frequency analysis is easily capable to find the correct key without trying out all possible ones. What is necessary to mitigate this problem as well? " + ] + }, + { + "cell_type": "markdown", + "id": "ab55c9fd-cfa5-4aca-afa6-b6c7c976cb3c", + "metadata": {}, + "source": [ + "Answers:\n", + "- Advantage: Finds key without having to try all possible ones; Disadvantage: Needs a somewhat large amount of data for statistical properties to emerge, as well as knowledge about the underlying statistics.\n", + "- In order to make statistical properties disapear, we need to introduce randomness into the cypher. The symbol frequencies of the cypher text should not depend on the original message." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Excercise_3/main.ipynb b/Excercise_3/main.ipynb deleted file mode 100644 index d8e9a62..0000000 --- a/Excercise_3/main.ipynb +++ /dev/null @@ -1,69 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# main" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'pandas'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m\n", - "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'pandas'" - ] - } - ], - "source": [ - "import pandas" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.9.18" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/Excercise_3/shakethatpear.txt b/Excercise_3/shakethatpear.txt new file mode 100644 index 0000000..01e5e64 --- /dev/null +++ b/Excercise_3/shakethatpear.txt @@ -0,0 +1,33 @@ +To be, or not to be, that is the question: +Whether 'tis nobler in the mind to suffer +The slings and arrows of outrageous fortune, +Or to take arms against a sea of troubles +And by opposing end them. To die--to sleep, +No more; and by a sleep to say we end +The heart-ache and the thousand natural shocks +That flesh is heir to: 'tis a consummation +Devoutly to be wish'd. To die, to sleep; +To sleep, perchance to dream--ay, there's the rub: +For in that sleep of death what dreams may come, +When we have shuffled off this mortal coil, +Must give us pause--there's the respect +That makes calamity of so long life. +For who would bear the whips and scorns of time, +Th'oppressor's wrong, the proud man's contumely, +The pangs of dispriz'd love, the law's delay, +The insolence of office, and the spurns +That patient merit of th'unworthy takes, +When he himself might his quietus make +With a bare bodkin? Who would fardels bear, +To grunt and sweat under a weary life, +But that the dread of something after death, +The undiscovere'd country, from whose bourn +No traveller returns, puzzles the will, +And makes us rather bear those ills we have +Than fly to others that we know not of? +Thus conscience doth make cowards of us all, +And thus the native hue of resolution +Is sicklied o'er with the pale cast of thought, +And enterprises of great pith and moment +With this regard their currents turn awry +And lose the name of action. \ No newline at end of file -- GitLab From 128cdecb0d933df00c4bf7ddaf549111aa09ffc5 Mon Sep 17 00:00:00 2001 From: Julius <julius.zocher@rwth-aachen.de> Date: Wed, 28 Feb 2024 09:52:25 +0100 Subject: [PATCH 03/23] update dependencies --- environment.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/environment.yml b/environment.yml index 44bf026..b1936a1 100644 --- a/environment.yml +++ b/environment.yml @@ -3,3 +3,6 @@ channels: - conda-forge dependencies: - pandas==2.0.0 + - numpy==1.26.2 + - matplotlib==3.8.2 + - pulp==2.7.0 -- GitLab From c2bc668661afb1fbe039971f1b82f9794c31fa89 Mon Sep 17 00:00:00 2001 From: Julius <julius.zocher@rwth-aachen.de> Date: Wed, 28 Feb 2024 14:21:26 +0100 Subject: [PATCH 04/23] ipdate ex2 --- ...Ex2_Battery_Optimization_noSolutions.ipynb | 320 +++++++++--------- 1 file changed, 164 insertions(+), 156 deletions(-) diff --git a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb index 915d5e0..5a059e6 100644 --- a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb +++ b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb @@ -2,8 +2,6 @@ "cells": [ { "cell_type": "markdown", - "id": "52b6c1bb", - "metadata": {}, "source": [ "# DEV Excercise 3\n", "Task 2 - Battery storage optimization\n", @@ -11,21 +9,25 @@ "In this task, an energy system consisting of a building with an electrical load (e.g. household appliances), PV system, battery storage and electricity grid connection is considered.\n", "24 time steps are considered, corresponding to the 24 hours of a day.\n", "Complete the code snippets where needed at places market with \"!!!\"." - ] + ], + "metadata": { + "collapsed": false + }, + "id": "7d6b628352d925e2" }, { "cell_type": "markdown", - "id": "6e26b8e3", - "metadata": {}, "source": [ "Definition of the individual components:" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "7c9c80da0ef98b06" }, { "cell_type": "code", - "execution_count": 16, - "id": "f93f1b55", - "metadata": {}, + "execution_count": 1, "outputs": [], "source": [ "# Time series of electrical load [kW]\n", @@ -42,134 +44,175 @@ "E_bat_kWh = 3 # capacity [kWh]\n", "P_bat_max_charge_kW = 1 # max charging power [kW] (charging efficiency of 100 % is assumed)\n", "P_bat_max_discharge_kW = 1 # max discharging power [kW] (discharging efficiency of 100 % is assumed)\n" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "b0157151aac2977a" }, { "cell_type": "markdown", - "id": "d8d3f3bb", - "metadata": {}, "source": [ "# Task 2 a)\n", "Plot the electrical demand, the electricity price as well as the PV generation for a 8 kWp plant. Use the python library matplotlib." - ] + ], + "metadata": { + "collapsed": false + }, + "id": "259a9633f492299a" }, { "cell_type": "code", - "execution_count": 17, - "id": "8f2b2111", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "execution_count": 2, + "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "# define the function\n", "def plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp):\n", - " # !!! insert function\n", - " plt.plot(el_demand_kW)\n", - " plt.plot(c_euro_kWh)\n", - " plt.plot(pv_pu)\n", - " plt.plot(pv_kWp)\n", - " plt.show()\n", + " \"\"\"\n", + " Plots the curves for electrical demand, the electricity price and the PV generation for a 8kWp plant.\n", + " :param el_demand_kW: time series of electrical load \n", + " :param c_euro_kWh: time series for costs of electricity from the grid\n", + " :param pv_pu: generation time series per unit [p.u.]\n", + " :param pv_kWp: peak power\n", + " \"\"\"\n", + " # !!! complete the code\n", + " \n", " pass\n", "\n", "# Call the function\n", "plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp)" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "a291137bccc17837" }, { "cell_type": "markdown", - "id": "40fc921d", - "metadata": {}, "source": [ "# Task 2 b)\n", "Calculate the costs of electricity supply assuming the PV plant and battery storage system are not operating. (Using numpy might be helpfull)" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "b3f112adafd4323a" }, { "cell_type": "code", - "execution_count": 19, - "id": "69488a00", - "metadata": {}, + "execution_count": 3, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The total electricity costs are 3.9 €\n" + "The total electricity costs are 0 €\n" ] } ], "source": [ "# define function\n", "def get_total_costs(energy, costs):\n", - " c_total = np.dot(np.array(energy),np.array(costs)) # !!! <-- insert calculation\n", + " \"\"\"\n", + " Returns the costs of electricity supply assuming the PV plant and battery storage system are not operating\n", + " :param energy: time series of electrical load \n", + " :param costs: time series for costs of electricity from the grid\n", + " :return: total cost value\n", + " \"\"\" \n", + " \n", + " c_total = 0 # !!! <-- insert calculation\n", " return c_total\n", "\n", "# call function\n", "c_total = get_total_costs(el_demand_kW, c_euro_kWh)\n", "print(f\"The total electricity costs are {round(c_total,2)} €\")" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "72143018a6eed25" + }, + { + "cell_type": "markdown", + "source": [ + "Result: The total electricity costs are 3.9 €" + ], + "metadata": { + "collapsed": false + }, + "id": "13535b9a1577d9fb" }, { "cell_type": "markdown", - "id": "9d4e20d6", - "metadata": {}, "source": [ "# Task 2 c)\n", "Calculate the costs of electricity considering a 8 kWp PV plant, but no battery storage system. Assume that no income is generated by feeding the PV generated electricity into the grid." - ] + ], + "metadata": { + "collapsed": false + }, + "id": "af8783fe2a5abeba" }, { "cell_type": "code", - "execution_count": 33, - "id": "e410b81f", - "metadata": {}, + "execution_count": 1, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "The total electricity costs are -16.82 €\n" + "ename": "NameError", + "evalue": "name 'get_total_costs' is not defined", + "output_type": "error", + "traceback": [ + "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[1;31mNameError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[1;32mIn[1], line 5\u001B[0m\n\u001B[0;32m 2\u001B[0m residuum_kW \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;66;03m# !!! <-- insert calculation\u001B[39;00m\n\u001B[0;32m 4\u001B[0m \u001B[38;5;66;03m# call cost calculating function\u001B[39;00m\n\u001B[1;32m----> 5\u001B[0m c_total_residuum \u001B[38;5;241m=\u001B[39m \u001B[43mget_total_costs\u001B[49m(residuum_kW, c_euro_kWh)\n\u001B[0;32m 6\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mThe total electricity costs are \u001B[39m\u001B[38;5;132;01m{\u001B[39;00m\u001B[38;5;28mround\u001B[39m(c_total_residuum,\u001B[38;5;241m2\u001B[39m)\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m €\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n", + "\u001B[1;31mNameError\u001B[0m: name 'get_total_costs' is not defined" ] } ], "source": [ "# calculate residuum\n", - "residuum_kW = np.array(el_demand_kW) - pv_kWp*np.array(pv_pu) # !!! <-- insert calculation \n", + "residuum_kW = 0 # !!! <-- insert calculation\n", "\n", "# call cost calculating function\n", "c_total_residuum = get_total_costs(residuum_kW, c_euro_kWh)\n", "print(f\"The total electricity costs are {round(c_total_residuum,2)} €\")" - ] + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-01-29T12:05:29.914599200Z", + "start_time": "2024-01-29T12:05:29.220590900Z" + } + }, + "id": "eab981a9d9c604fe" + }, + { + "cell_type": "markdown", + "source": [ + "Result: The total electricity costs are 1.59 €" + ], + "metadata": { + "collapsed": false + }, + "id": "15d46ddd46dbad9b" }, { "cell_type": "markdown", - "id": "e432595f", - "metadata": {}, "source": [ "# Task 2d)\n", "In the following, an optimization problem is set up to optimize the operation of the battery in such a way that the electricity supply for the house is as cost-effective as possible." - ] + ], + "metadata": { + "collapsed": false + }, + "id": "a34b5d21c3844d90" }, { "cell_type": "code", - "execution_count": 23, - "id": "eedebac7", - "metadata": {}, + "execution_count": 5, "outputs": [], "source": [ "# Import of necessary packages\n", @@ -210,53 +253,33 @@ " model.solve()\n", "\n", " return model, buy, soc, feedin" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "9bc932d40fa4a87f" }, { "cell_type": "markdown", - "id": "fe89f489", - "metadata": {}, "source": [ "Calculate the costs of electricity considering a 8 kWp PV plant and 3 kWh battery storage system. Assume that no income is generated by feeding the PV generated electricity into the grid. Plot the resulting state of charge (SOC) and buy time series and compare them to the other time series.\n" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "4716844fbe8d1a33" }, { "cell_type": "code", - "execution_count": 25, - "id": "4e6625bc", - "metadata": {}, + "execution_count": 6, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The total electricity costs are 0.55 €\n", + "The total electricity costs are 0 €\n", "The total electricity costs are 0.55 €\n" ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" } ], "source": [ @@ -285,58 +308,53 @@ "plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp)\n", "\n", "# !!! insert plot for Battery SOC\n", - "plt.plot(soc_results)\n", "\n", "# !!! insert plot for electricity bought\n", - "plt.plot(buy_results)\n", "\n", "\n", "plt.show()" - ] + ], + "metadata": { + "collapsed": false + }, + "id": "36908ba960de9d4b" }, { "cell_type": "markdown", - "id": "312a055f", - "metadata": {}, "source": [ "The SOC of the battery starts and ends at 50% of the maximum capacity, as this is specified by the constraints. Initially, the battery discharges as no PV power is generated. It is sufficient to charge the battery in the last hours of the day, as the size of the battery is comparatively small. It can be seen that the grid power is drawn in the time steps when the grid power is most favorable." - ] + ], + "metadata": { + "collapsed": false + }, + "id": "f7e51d061cdba850" }, { "cell_type": "markdown", - "id": "8c3cc635", - "metadata": {}, "source": [ "# Task 2 e)\n", "Change the battery optimization function (1 Variable, 1 Objective, 1 Constraint) below so that the maximium (single peak value, not sum of all values!) feed in from the pv plant to the grid gets minimized. How much was the maximum feed in without battery operation, with cost minimizing battery operation and with feed-in minimizing battery operation? Plot the resulting feed-in time series." - ] + ], + "metadata": { + "collapsed": false + }, + "id": "e323c8dc005ac6c6" }, { "cell_type": "code", - "execution_count": 45, - "id": "4e8c2c60", - "metadata": {}, + "execution_count": 7, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "The maximum feed-in without battery operation is 9.1 kW.\n", - "The maximum feed-in with cost minimizing battery operation is 7.2 kW.\n", - "The maximum feed-in with feed-in minimizing battery operation is 6.2 kW.\n" + "ename": "TypeError", + "evalue": "'int' object is not subscriptable", + "output_type": "error", + "traceback": [ + "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[1;32mIn[7], line 48\u001B[0m\n\u001B[0;32m 45\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m model, buy, soc, feedin\n\u001B[0;32m 47\u001B[0m \u001B[38;5;66;03m# call optimization function\u001B[39;00m\n\u001B[1;32m---> 48\u001B[0m model, buy, soc, feedin \u001B[38;5;241m=\u001B[39m \u001B[43moptimze_battery_operation_PV\u001B[49m\u001B[43m(\u001B[49m\u001B[43mel_demand_kW\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpv_kWp\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpv_pu\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mE_bat_kWh\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mP_bat_max_charge_kW\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mP_bat_max_discharge_kW\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mc_euro_kWh\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 50\u001B[0m \u001B[38;5;66;03m# read results\u001B[39;00m\n\u001B[0;32m 51\u001B[0m feedin_results \u001B[38;5;241m=\u001B[39m []\n", + "Cell \u001B[1;32mIn[7], line 40\u001B[0m, in \u001B[0;36moptimze_battery_operation_PV\u001B[1;34m(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh)\u001B[0m\n\u001B[0;32m 38\u001B[0m \u001B[38;5;66;03m# !!! insert new constraint\u001B[39;00m\n\u001B[0;32m 39\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m t \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mrange\u001B[39m(\u001B[38;5;241m23\u001B[39m):\n\u001B[1;32m---> 40\u001B[0m model \u001B[38;5;241m+\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[43mmax_pv_feed_in\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m]\u001B[49m \u001B[38;5;241m>\u001B[39m\u001B[38;5;241m=\u001B[39m feedin[t]\n\u001B[0;32m 42\u001B[0m \u001B[38;5;66;03m# Solve the optimization problem\u001B[39;00m\n\u001B[0;32m 43\u001B[0m model\u001B[38;5;241m.\u001B[39msolve()\n", + "\u001B[1;31mTypeError\u001B[0m: 'int' object is not subscriptable" ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAEGCAYAAABvtY4XAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAABU8klEQVR4nO3dd1iUx9rA4d/s0rsIgg1RsdNERYoae9QYS2JMMc2cJCfRmF40vZzkM8f0dlLV9GKMJbYYExWNvSBYwYIiIgIK0lnY+f54AUHKLspS574uLuGtj8vyMMw784yQUqIoiqI0P7qGDkBRFEWxDJXgFUVRmimV4BVFUZopleAVRVGaKZXgFUVRmimrhg6gPA8PD+nr69vQYSiKojQZu3fvTpNSela1r1EleF9fX3bt2tXQYSiKojQZQoiT1e1TXTSKoijNlErwiqIozZRK8IqiKM1Uo+qDV5SqGAwGTp8+TX5+fkOHoigNxs7Ojg4dOmBtbW32OSrBK43e6dOncXZ2xtfXFyFEQ4ejKPVOSkl6ejqnT5+mc+fOZp+numiURi8/P5/WrVur5K60WEIIWrduXeu/YlWCV5oEldyVlu5KfgZUgleUKySlJD27gHxDcUOHoihVUgleUUx47LHHeO+998q+vvbaa7n33nu5kGsgKSOP+2c+wguvzeXX35Yyd+5cAJYuXcrBgwfLzhk6dGidTeJ74403qt3n6+tLQEAAwcHBBAQEsGzZslpdLyMjg08++aRO4lQankrwimJCZGQkW7ZsAcBoNJKWlsaBAwc4dzEfe2s9B6N30jOoP91Dh3LrfbPIKyyulODrUk0JHmD9+vVER0fz66+/8vDDD9fqeleS4KWUGI3GWp2j1A+V4BXFhIiICLZu3QrAgQMH8Pf3x87BkbT087jZCY7GHWHyqEGsX76IOU88xqJV61i6bDlPPvkUwcHBHDt2DIBFixYRGhpK9+7d2bRpE6A9QJ4+fToBAQH07duX9evXA7Bw4UIeeuihshjGjx/Phg0bmD17Nnl5eQQHBzNt2rQa47548SKtWrUq+3rSpEn069ePPn368PnnnwNUut7s2bM5duwYwcHBPPXUUwDMmzePAQMGEBgYyEsvvQRAQkICPXr04M4778Tf35/XXnuNRx99tOxeX3zxBY899tjVvOxKHVDDJJUm5ZXfD3DwzMU6vWbvdi68dH2fave3a9cOKysrTp06xZYtWxgYFoZD3AkOx+yGDC8CAgJwsLfD1cEaN0drrh1+DUNHjWHwiGu58cYptHGxBaCoqIgdO3awatUqXnnlFdatW8fHH3+MEILY2FgOHz7M6NGjiYuLqzaWuXPn8tFHHxEdHV3tMcOGDUNKyfHjx/nll1/Kts+fPx93d3fy8vIYMGAAN954Y6XrJSQksH///rKv165dS3x8PDt27EBKyYQJE4iKisLHx4f4+Hi+/vprwsLCyM7OJigoiHnz5mFtbc2CBQv47LPPzP8mKBahEryimCEiIoItW7awZcsW7nngIaRja47E7OJCkjuRkZFlx+mEwMvFDld7a9zsrckpLOLoOQP5hmLGjp8AQL9+/UhISABg8+bNzJo1C4CePXvSqVOnGhO8OdavX4+HhwfHjh1jxIgRDB06FCcnJz744AOWLFkCQGJiIvHx8bRu3brGa61du5a1a9fSt29fALKzs4mPj8fHx4dOnToRFhYGgJOTE8OHD2fFihX06tULg8FAQEDAVf0/lKunErzSpNTU0rak0n742NhYWnf0I8zdi9++/gwXFxemT59e6XghBK4ONvT0diE9pwCjhNRcI8dTs9EXSYqKimq8n5WVVYV+7SuZxdu1a1e8vLw4ePAgubm5rFu3jq1bt+Lg4MDQoUPNuqaUkjlz5vDvf/+7wvaEhAQcHR0rbLv33nt544036NmzZ5WviVL/VB+8opghIiKCFStW4OzqhhFBj05tycjIYOvWrURERFQ63tnZmaysLPQ6QRtnO+xt9Hg42ZJvMJKQnoNRSgAGDx7M999/D0BcXBynTp2iR48e+Pr6Eh0djdFoJDExkR07dpRd29raGoPBYDLmc+fOceLECTp16kRmZiatWrXCwcGBw4cPs23btiqvVxp3qWuvvZb58+eTnZ0NQFJSEufOnavyfgMHDiQxMZEffviBW2+91WR8iuWpFryimCEgIIC0tDRGTbgRR1srnOysCQgIIDs7Gw8Pj0rH33LLLdx333188MEH/PrrrwiglaMNPb2dyc+6QLFRUmw0MmPGDB588EECAgKwsrJi4cKF2NraEhkZSefOnenduze9evUiJCSk7Nr3338/gYGBhISElP1yKG/YsGHo9XoMBgNz587Fy8uLMWPG8Omnn9KrVy969OhR1rVS1fUiIyPx9/dn7NixzJs3j0OHDhEeHg5oXTHfffcder2+ytdp6tSpREdHV3i4qzQcIUtaEo1B//79pVrwQ7ncoUOH6NWrV0OHQWpWAcmZeXTxdMLJ9srbRnmFRcSfy8bb1Y42znZ1GGHDGz9+PI899hgjRoxo6FCapap+FoQQu6WU/as6XnXRKIoZio2S1KwCnGytriq5A9jbaNdIyyrEaGw8DayrkZGRQffu3bG3t1fJvRFRXTSKYob0nAKKjEa8XBzq5HptnG05npbDhdxCWjvZ1sk1G5Kbm9tVj/5R6p5qwSuKCcVGSVpWAc521jheZeu9lKOtFQ42VqRmF9CYukmV5kUleEUxIT27gCKjxMul7lraQgg8nW0pLDKSmWd6RIyiXAmV4BWlBsVGI6nZBbjYWeNgU7c9mi52Vtha6UnNUq14xTJUgleUGqRlF1Jcx633UqWt+DxDMdkFNU98UpQroRK8olSjqNhIWnYB7//neT775KOy7aXlgks98cQTvPPOOyxfvrzW5YLdHKyx1us4l1UAaJOdxo0bR7du3QgJCWHq1KmkpKTUKm5TFSGFENx+++2X/p9FRXh6ejJ+/HiACv+P6pw5c4YpU6bUKq4XX3yRdevWXfH+2lBlk0tIKRvNR79+/aSiXO7gwYMNct/kjDy5L/GC/P7Hn+VNN90kpZSyuLhYhoSEyLCwsLLjwsLC5NatWyuce9ddd8lFixaVfX3NNdfInTt3Vnmfcxfz5b7ECzItI0v6+fnJ5cuXl+1bv369jI2NrVXcJ06ckH369Kl2v6OjowwKCpK5ublSSilXrVolg4KC5HXXXVer+zRmnTp1kqmpqVJKKQ8fPix9fHxMnuPo6Fj2uanXsCpGo1EWFxfXLtBaqupnAdglq8mpqgWvKFUoKjaSnl2Aq701Q4cMqlQu2NnZmQsXLlBQUMChQ4cICQkpK/G7ZcsWli9fzlNPmS4XDODuaINeJ/hq4beEh4dz/fXXl+0bOnQo/v7+1ZYVPnDgAKGhoQQHBxMYGEh8fHyVJX8vN27cOFauXAnAjz/+WKG0QPlSxXfffTcPP/wwERERdOnShV9//RXQatH4+/uXHT9p0iRGjRqFr68vH330Ee+88w59+/YlLCyM8+fPl13r119/ZdeuXQQHB5e1rkuXoivdD1oL/KWXXiIkJISAgAAOHz4MQGpqKqNGjaJPnz7ce++9dOrUibS0tBq/ly25bLIaB680Latnw9nYur2mdwCMrdglkZZdQLGUeLnYYWftWKFccHh4OElJSWzduhVXV1cCAgKwsbEpOzciIoIJEyYwfvz4Ct0YVZULBtDrBK2dbIndv5+g4L5VhlhdWeFPP/2URx55hGnTplFYWEhxcTFz586tUPK3Krfccguvvvoq48ePJyYmhnvuuafCL53ykpOT2bx5M4cPH2bChAlVds3s37+fvXv3kp+fj5+fH2+++SZ79+7lscce45tvvqmQ9Pr3718W21NPPcWYMWOqvK+Hhwd79uzhk08+4a233uLLL7/klVdeYfjw4cyZM4c1a9bw1VdfVft/VGWTVYJXlEq0vvdC3OxtsLPWaq6ULxf8+OOPk5SUxJYtW3B1da1QLrgmN9xwA1CxXHApD0cbhKDah63VlRUODw/n9ddf5/Tp09xwww1069bNrFgCAwNJSEjgxx9/ZNy4cTUeO2nSJHQ6Hb179672ecCwYcNwdnbG2dkZV1fXsr9CAgICiImJqfKcn3/+mT179rB27doq95d/vX777TdAex1KSx6PGTOmxpo3qmyySvBKUzO25od/daF08lGbciNnypcL9vf3p2PHjrz99tvVlguuiq2tdj29Xl+pXLCVXkdQgD8bNm6ksMiIjZV5vae33XYbAwcOZOXKlYwbN47PPvuMLl26mHXuhAkTePLJJ9mwYQPp6ekm4waqHc5Z/hidTlf2tU6nq7I08v79+3n55ZeJioqqtnBZTa9XbbTksskW7YMXQjwmhDgghNgvhPhRCNG8KispzY6h2Eh6diFuDpda73CpXLC7uzt6vR53d3ezygXXxr1338G+XTv4afHSsm1RUVHs37+/2rLCx48fp0uXLjz88MNMnDiRmJgYs+99zz338NJLL9V7CzMjI4Nbb72Vb775Bk9Pz1qdGxkZWdbdsnbtWi5cuGDynJZcNtliCV4I0R54GOgvpfQH9MAtlrqfotQFbdKRViumvNJyweXL7AYEBODq6lptueB58+bRt2/fsoesprg6O/H1T4v5/H+f0K1bN3r37s0nn3yCp6cnM2bMwGg0EhAQwM0331xWVviXX37B39+f4OBg9u/fz5133knr1q3LSv5W95AVoEOHDmYtyl3Xli1bxsmTJ7nvvvvKHraa66WXXmLt2rX4+/uzaNEivL29cXZ2rvLYYcOGERwczLBhwyqUTS4qKqJXr17Mnj27yrLJ06ZNq/Qajh49mttuu43w8HACAgKYMmVKjb9Ep06dSmRkZIOXTbZYueCSBL8NCAIuAkuBD6SUVXe4ocoFK1Wrr3LBhmIjR85m4WpvTUf3uikqVlv5hmLiUrLwcrHDy0X9wXu5goIC9Ho9VlZWbN26lQcffLDGh8kNxVJlk2tbLthiffBSyiQhxFvAKSAPWFtVchdC3A/cD+Dj42OpcBTFpLLWuwVmrZrLzlqPi501adkFeDjZoteJBoulMTp16hRTp07FaDRiY2PDF1980dAhVZCRkUFoaChBQUGNomyyxRK8EKIVMBHoDGQAi4QQt0spvyt/nJTyc+Bz0FrwlopHUWpSWGQkPaeQVo7W2FpV/dCvvng623Ix1cCFnEI8nJt+KeG61K1bN/bu3dvQYVSrsZVNtuRD1pHACSllqpTSAPwGVH4apSiNwLmL2kiKy/veG4KjrRWOtlopYaOFulCVlsGSCf4UECaEcBDaVLURwCEL3k9RrkieoVhbeMPRBpsGbr2X8nS2xVBsJCNXlRJWrpzFEryUcjvwK7AHiC251+eWup+iXKmzmfnodKJRtN5LOdtaYWetSgkrV8ei4+CllC9JKXtKKf2llHdIKQsseT9Fqa2sfANZ+QbaONthpW88pZmE0H7hFBQVczFflRJWrkzjeUcrSj2TUpKcmY+NlY7WTjbVHvfYY4/x3nvvlX1dl+WCy0tISMDe3r5sbPjQiFAwFl1VK758UbDL1bY874YNGxBC8OWXX5Zti46ORgjBW2+9ZfY1zSlHfLlx48aRkZFxxfvNVf57EBQUREREBEeOHDF5zg8//FD2dXR0NKtWrbrqWOqCSvBKi3Uh10C+oRhvFzt0ovrhiKVlCgCMRiNpaWkcOHCgbP+WLVvKCozNnj0bqJzgzdW1a1eio6PLPtq7O5NbWEROYXGtr2XKq6++ysiRI2t1jr+/f4XCXT/++CNBQUG1umb518lcq1atws3N7Yr310bp92Dfvn3cddddFerEV6UuEvzVlGKoiUrwSotkNEpSLubjYGOFq711jcdGRERYtFxwTVo52LB903qGDIokJCSEm266qWy6/O7du7nmmmvo168f1157LcnJyWXbg4KCCAoK4uOPP6722uaU571cp06dyM/PJyUlBSkla9asYezYsbW65uXliB988EHCwsLo0qULGzZs4J577qFXr17cfffdZdf19fUlLS2NTz/9tOwvnM6dOzNs2LAK+xMSEujVqxf33Xcfffr0YfTo0eTl5QGwc+dOAgMDy0oAV/eXTXnlSw0nJCQwePBgQkJCCAkJKfulP3v2bDZt2kRwcDBvvvkmL774Ij///DPBwcH8/PPP5OTkcM899xAaGkrfvn3LFh9ZuHAhEyZMYPjw4YwYMYI777yTpUuXlt172rRpZi1UUhNVbExpUt7c8SaHz1edfGqjsNiIociInbWePh69eCb0mWqPbdeunUXLBZdXWoMctL8cXnnlFeZ/9DaffP8bQb7efPDuW7zzzjvMmTOHWbNmsWzZMjw9Pfn555957rnnmD9/PtOnT+ejjz5iyJAhNZYquFxV5XmrMmXKFBYtWkTfvn0JCQmpUGjsSq554cIFtm7dyvLly5kwYQL//PMPX375JQMGDCA6OrpCKYMHHniABx54AIPBwPDhw3n88ccrXS8+Pp4ff/yRL774gqlTp7J48WJuv/12pk+fzhdffEF4eHiNf0GUfg+ysrLIzc1l+/btALRp04Y///wTOzs74uPjufXWW9m1axdz587lrbfeYsWKFQB4eXmxa9cuPvpIWwXs2WefZfjw4cyfP79sIlTpXzl79uwhJiYGd3d3Nm7cyLvvvsukSZPIzMxky5YtfP3119XGaQ6V4JUWR0owFBnR64TZM0UtXS64VGn3QKkVK1YQf+Qwd08eg04noLiI8PBwjhw5wv79+xk1ahQAxcXFtG3bloyMDDIyMhgyZAgAd9xxB6tXr651fKXleasydepUbr75Zg4fPsytt95a1pK90mtef/31CCEICAjAy8urrPhZnz59SEhIqLJWzSOPPMLw4cMrLI5SqnPnzmXnlL7WGRkZZGVlER4eDmhVOEsT8uXKfw9+/vln7r//ftasWYPBYOChhx4iOjoavV5v9oSmtWvXsnz58rLnFPn5+Zw6dQqAUaNG4e7uDsA111zDjBkzSE1NZfHixdx4441YWV1dilYJXmlSamppmyvpQi7ncwx093LC1tq8ce+WLhdcHSklo0aN4r3PFpByMZ8OrRxwd7QhNjaWPn36lHUdlarpQeP06dPZu3cv7dq1q7KP2Nz4vL29sba25s8//+T999+vMcGbc83ypYUvLztc1TkLFy7k5MmTZS3k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\n", - "text/plain": [ - "<Figure size 432x288 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" } ], "source": [ @@ -355,11 +373,11 @@ " feedin = LpVariable.dicts(\"feedin\", range(24), lowBound=0) # The amount of electricity (in kW) sold to the grid at time t\n", " consumed_pv = LpVariable.dicts(\"consumed_pv\", range(24), lowBound=0) # The amount of electricity (in kW) consumed directly from PV at time t\n", "\n", - " # !!! insert new decision variable\n", - " max_pv_feed_in = LpVariable(\"max_pv_feed_in\", lowBound=0)\n", + " # !!! insert new variable\n", + " max_pv_feed_in = 0\n", "\n", - " # !!! insert new objective function\n", - " model += max_pv_feed_in, \"Minimize_Max_Feedin\" #lpSum(0)\n", + " # !!! insert new Objective Function\n", + " model += lpSum(0)\n", "\n", " # Constraints\n", " model += soc[0] == E_bat_kWh/2\n", @@ -379,7 +397,7 @@ "\n", " # !!! insert new constraint\n", " for t in range(23):\n", - " model += max_pv_feed_in >= feedin[t]\n", + " model += max_pv_feed_in[0] >= feedin[t]\n", "\n", " # Solve the optimization problem\n", " model.solve()\n", @@ -396,46 +414,36 @@ " feedin_results.append(feedin[i].value())\n", "\n", "# max feed-in without battery:\n", - "max_feedin_1 = max(pv_kWp * np.array(pv_pu) + np.array(el_demand_kW))\n", - "\n", + "max_feedin_1 = 0 # !!! <-- insert calculation\n", "print(f\"The maximum feed-in without battery operation is {max_feedin_1} kW.\")\n", "\n", "# max feed-in with cost minimizing battery operation:\n", "max_feedin_2 = 0 # !!! <-- insert calculation\n", - "max_feedin_2 = max(feedin_cost_minimizing_results)\n", "print(f\"The maximum feed-in with cost minimizing battery operation is {max_feedin_2} kW.\")\n", "\n", "# max feed-in with feed-in minimizing battery operation:\n", - "max_feedin_3 = max(feedin_results)#0 # !!! <-- insert calculation\n", + "max_feedin_3 = 0 # !!! <-- insert calculation\n", "print(f\"The maximum feed-in with feed-in minimizing battery operation is {max_feedin_3} kW.\")\n", "\n", "# !!! insert plots\n", - "plt.plot(range(24), pv_kWp * np.array(pv_pu) + np.array(el_demand_kW), label='Without Battery')\n", - "plt.plot(range(24), feedin_cost_minimizing_results, label='With Cost Minimizing Battery')\n", - "plt.plot(range(24), feedin_results, label='With Feed-in Minimizing Battery')\n", "\n", - "plt.xlabel('Time (hours)')\n", - "plt.ylabel('Feed-in (kW)')\n", - "plt.legend()\n", "\n", "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "01ca0a8e", - "metadata": {}, - "outputs": [], - "source": [] + ], + "metadata": { + "collapsed": false + }, + "id": "649d87d692c5365" }, { "cell_type": "code", "execution_count": null, - "id": "97f4c29d", - "metadata": {}, "outputs": [], - "source": [] + "source": [], + "metadata": { + "collapsed": false + }, + "id": "21ab0d83302acf04" } ], "metadata": { @@ -447,14 +455,14 @@ "language_info": { "codemirror_mode": { "name": "ipython", - "version": 3 + "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" + "pygments_lexer": "ipython2", + "version": "2.7.6" } }, "nbformat": 4, -- GitLab From 87189d614fa1549f3d390c67f148d3c55ffb8469 Mon Sep 17 00:00:00 2001 From: "f.tischbein" <f.tischbein@iaew.rwth-aachen.de> Date: Wed, 28 Feb 2024 15:29:13 +0100 Subject: [PATCH 05/23] Update Exercise 2 --- ...> 2024_02_23_DEV_UE2_A2_v2_students.ipynb} | 318 +++++++++--------- 1 file changed, 150 insertions(+), 168 deletions(-) rename Excercise_2/{2023_12_01_DEV_UE2_A2_v1.0_students.ipynb => 2024_02_23_DEV_UE2_A2_v2_students.ipynb} (51%) diff --git a/Excercise_2/2023_12_01_DEV_UE2_A2_v1.0_students.ipynb b/Excercise_2/2024_02_23_DEV_UE2_A2_v2_students.ipynb similarity index 51% rename from Excercise_2/2023_12_01_DEV_UE2_A2_v1.0_students.ipynb rename to Excercise_2/2024_02_23_DEV_UE2_A2_v2_students.ipynb index 790a5d6..c489a49 100644 --- a/Excercise_2/2023_12_01_DEV_UE2_A2_v1.0_students.ipynb +++ b/Excercise_2/2024_02_23_DEV_UE2_A2_v2_students.ipynb @@ -46,15 +46,15 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": { "collapsed": true, "pycharm": { "name": "#%%\n" }, "ExecuteTime": { - "end_time": "2024-01-03T15:01:38.782849Z", - "start_time": "2024-01-03T15:01:34.983511400Z" + "end_time": "2024-02-23T12:58:40.909857800Z", + "start_time": "2024-02-23T12:58:28.941463400Z" } }, "outputs": [], @@ -65,18 +65,11 @@ "from scipy.optimize import curve_fit" ] }, - { - "cell_type": "markdown", - "source": [], - "metadata": { - "collapsed": false - } - }, { "cell_type": "markdown", "source": [ "### Predefine functions\n", - "It is good programming practice to define functions at the beginning that you want to use again and again in the course of the code. You can find instructions with examples for defining functions under the following [link](https://www.w3schools.com/python/python_functions.asp). In the course of this exercise, you will need to complete functions at this point. " + "It is good programming practice to define functions at the beginning that you want to use again and again in the course of the code. You can find instructions with examples for defining functions under the following [link](https://www.w3schools.com/python/python_functions.asp). For reasons of overview, however, we will always define these in the respective task section first. As an example, we give you the function <code> round_up(x, decimals) </code>. This function always rounds up values and will be used more frequently throughout the code." ], "metadata": { "collapsed": false, @@ -87,7 +80,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "outputs": [], "source": [ "def round_up(x, decimals: int):\n", @@ -100,85 +93,10 @@ " \"\"\"\n", " value = np.ceil(pow(10, decimals)*x) / pow(10, decimals)\n", "\n", - " return value\n", - "\n", - "def uri(U,I):\n", - " \"\"\"\n", - " Returns the value for the resistance following Ohm's law U=R*I\n", - " :param U: voltage value\n", - " :param I: current value\n", - " :return: resistance value\n", - " \"\"\"\n", - " # Complete the code\n", - " return\n", - "\n", - "def calc_sig_R(U, I, sig_I):\n", - " \"\"\"\n", - " Returns the value of the uncertainty of the resistance according to Ohm's law and Gaussian error propagation\n", - " :param U: voltage value\n", - " :param I: current value\n", - " :param sig_I: uncertainty of the resistance\n", - " :return: \n", - " \"\"\"\n", - " # Complete the code\n", - " return \n", - "\n", - "def weighted_mean(x, sig_x):\n", - " \"\"\"\n", - " Returns the weighted mean of variables x and their uncertainties sig_x\n", - " :param x: array with x values\n", - " :param sig_x: array with uncertainty of respective x value\n", - " :return: weighted mean\n", - " \"\"\"\n", - " # Complete the code\n", - "\n", - " return \n", - "\n", - "def sig_weighted_mean(sig_x):\n", - " \"\"\"\n", - " Returns the uncertainty of the weighted mean of variables x and their uncertainties sig_x\n", - " :param sig_x: array with uncertainty of respective x value\n", - " :return: uncertainty of weighted mean\n", - " \"\"\"\n", - " # Complete the code\n", - "\n", - " return \n", - "\n", - "\n", - "def ml_estimator(x, y, sig_y):\n", - " \"\"\"\n", - " Returns the parameter m that is determined by using the maximum likelihood method.\n", - " :param x:\n", - " :param y:\n", - " :param sigma:\n", - " :return: m\n", - " \"\"\"\n", - " # Complete the code\n", - "\n", - " return \n", - "\n", - "def chi2_formula(x, y, sig_y, R):\n", - " \"\"\"\n", - " Formula to calculate the Chi^2 value in the case of the relationship y = x/R\n", - " :param x: x values\n", - " :param y: y values\n", - " :param sig_y: uncertainty of y values\n", - " :param m: slope\n", - " :return: \n", - " \"\"\"\n", - " # Complete the code\n", - "\n", - " return \n" + " return value" ], "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - }, - "ExecuteTime": { - "end_time": "2024-01-03T15:01:44.000874400Z", - "start_time": "2024-01-03T15:01:43.987393800Z" - } + "collapsed": false } }, { @@ -193,36 +111,12 @@ }, { "cell_type": "code", - "execution_count": 6, - "outputs": [ - { - "ename": "ImportError", - "evalue": "Missing optional dependency 'openpyxl'. Use pip or conda to install openpyxl.", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)", - "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\compat\\_optional.py:142\u001B[0m, in \u001B[0;36mimport_optional_dependency\u001B[1;34m(name, extra, errors, min_version)\u001B[0m\n\u001B[0;32m 141\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 142\u001B[0m module \u001B[38;5;241m=\u001B[39m \u001B[43mimportlib\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mimport_module\u001B[49m\u001B[43m(\u001B[49m\u001B[43mname\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 143\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m:\n", - "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python38\\lib\\importlib\\__init__.py:127\u001B[0m, in \u001B[0;36mimport_module\u001B[1;34m(name, package)\u001B[0m\n\u001B[0;32m 126\u001B[0m level \u001B[38;5;241m+\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m1\u001B[39m\n\u001B[1;32m--> 127\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43m_bootstrap\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_gcd_import\u001B[49m\u001B[43m(\u001B[49m\u001B[43mname\u001B[49m\u001B[43m[\u001B[49m\u001B[43mlevel\u001B[49m\u001B[43m:\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpackage\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mlevel\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[1;32m<frozen importlib._bootstrap>:1014\u001B[0m, in \u001B[0;36m_gcd_import\u001B[1;34m(name, package, level)\u001B[0m\n", - "File \u001B[1;32m<frozen importlib._bootstrap>:991\u001B[0m, in \u001B[0;36m_find_and_load\u001B[1;34m(name, import_)\u001B[0m\n", - "File \u001B[1;32m<frozen importlib._bootstrap>:973\u001B[0m, in \u001B[0;36m_find_and_load_unlocked\u001B[1;34m(name, import_)\u001B[0m\n", - "\u001B[1;31mModuleNotFoundError\u001B[0m: No module named 'openpyxl'", - "\nDuring handling of the above exception, another exception occurred:\n", - "\u001B[1;31mImportError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[1;32mIn[6], line 3\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[38;5;66;03m### First, the data needs to be loaded from the given xlsx-file. Note that all datatypes shall be set to float.\u001B[39;00m\n\u001B[1;32m----> 3\u001B[0m data \u001B[38;5;241m=\u001B[39m \u001B[43mpd\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mread_excel\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mmeasurement_data.xlsx\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mindex_col\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdtype\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mfloat\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[0;32m 5\u001B[0m \u001B[38;5;66;03m### Define arrays with the corresponding voltage and current values for later use.\u001B[39;00m\n\u001B[0;32m 6\u001B[0m U \u001B[38;5;241m=\u001B[39m data\u001B[38;5;241m.\u001B[39mloc[:, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mvoltage\u001B[39m\u001B[38;5;124m\"\u001B[39m]\n", - "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\io\\excel\\_base.py:478\u001B[0m, in \u001B[0;36mread_excel\u001B[1;34m(io, sheet_name, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, parse_dates, date_parser, date_format, thousands, decimal, comment, skipfooter, storage_options, dtype_backend)\u001B[0m\n\u001B[0;32m 476\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(io, ExcelFile):\n\u001B[0;32m 477\u001B[0m should_close \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mTrue\u001B[39;00m\n\u001B[1;32m--> 478\u001B[0m io \u001B[38;5;241m=\u001B[39m \u001B[43mExcelFile\u001B[49m\u001B[43m(\u001B[49m\u001B[43mio\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mstorage_options\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mengine\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mengine\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 479\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m engine \u001B[38;5;129;01mand\u001B[39;00m engine \u001B[38;5;241m!=\u001B[39m io\u001B[38;5;241m.\u001B[39mengine:\n\u001B[0;32m 480\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[0;32m 481\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mEngine should not be specified when passing \u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 482\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124man ExcelFile - ExcelFile already has the engine set\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 483\u001B[0m )\n", - "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\io\\excel\\_base.py:1513\u001B[0m, in \u001B[0;36mExcelFile.__init__\u001B[1;34m(self, path_or_buffer, engine, storage_options)\u001B[0m\n\u001B[0;32m 1510\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mengine \u001B[38;5;241m=\u001B[39m engine\n\u001B[0;32m 1511\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mstorage_options \u001B[38;5;241m=\u001B[39m storage_options\n\u001B[1;32m-> 1513\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_reader \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_engines\u001B[49m\u001B[43m[\u001B[49m\u001B[43mengine\u001B[49m\u001B[43m]\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_io\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstorage_options\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mstorage_options\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\io\\excel\\_openpyxl.py:548\u001B[0m, in \u001B[0;36mOpenpyxlReader.__init__\u001B[1;34m(self, filepath_or_buffer, storage_options)\u001B[0m\n\u001B[0;32m 533\u001B[0m \u001B[38;5;129m@doc\u001B[39m(storage_options\u001B[38;5;241m=\u001B[39m_shared_docs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mstorage_options\u001B[39m\u001B[38;5;124m\"\u001B[39m])\n\u001B[0;32m 534\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__init__\u001B[39m(\n\u001B[0;32m 535\u001B[0m \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m 536\u001B[0m filepath_or_buffer: FilePath \u001B[38;5;241m|\u001B[39m ReadBuffer[\u001B[38;5;28mbytes\u001B[39m],\n\u001B[0;32m 537\u001B[0m storage_options: StorageOptions \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[0;32m 538\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[0;32m 539\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[0;32m 540\u001B[0m \u001B[38;5;124;03m Reader using openpyxl engine.\u001B[39;00m\n\u001B[0;32m 541\u001B[0m \n\u001B[1;32m (...)\u001B[0m\n\u001B[0;32m 546\u001B[0m \u001B[38;5;124;03m {storage_options}\u001B[39;00m\n\u001B[0;32m 547\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n\u001B[1;32m--> 548\u001B[0m \u001B[43mimport_optional_dependency\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mopenpyxl\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[0;32m 549\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(filepath_or_buffer, storage_options\u001B[38;5;241m=\u001B[39mstorage_options)\n", - "File \u001B[1;32m~\\Documents\\Tools\\DEV\\.venv\\lib\\site-packages\\pandas\\compat\\_optional.py:145\u001B[0m, in \u001B[0;36mimport_optional_dependency\u001B[1;34m(name, extra, errors, min_version)\u001B[0m\n\u001B[0;32m 143\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m:\n\u001B[0;32m 144\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m errors \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mraise\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[1;32m--> 145\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m(msg)\n\u001B[0;32m 146\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m 148\u001B[0m \u001B[38;5;66;03m# Handle submodules: if we have submodule, grab parent module from sys.modules\u001B[39;00m\n", - "\u001B[1;31mImportError\u001B[0m: Missing optional dependency 'openpyxl'. Use pip or conda to install openpyxl." - ] - } - ], + "execution_count": 3, + "outputs": [], "source": [ - "### First, the data needs to be loaded from the given xlsx-file as a pandas dataframe called 'data'. Note that all datatypes shall be set to float.\n", + "### First, the data needs to be loaded from the given xlsx-file. Note that all datatypes shall be set to float.\n", "\n", - "data = ...\n", + "data = \n", "\n", "### Define arrays with the corresponding voltage and current values for later use.\n", "U = \n", @@ -233,8 +127,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-01-03T15:02:26.578566600Z", - "start_time": "2024-01-03T15:02:26.440889500Z" + "end_time": "2024-02-23T13:00:28.694732900Z", + "start_time": "2024-02-23T13:00:28.119399700Z" } } }, @@ -243,16 +137,51 @@ "source": [ "### Task 2b\n", "After the data has been read in, the resistance and its uncertainty are to be determined for the value pairs. \n", - "Add the corresponding code to the functions in the cell above to calculate the resistance with the function <code> def uri(U,I) </code> and the uncertainty with the function def <code> def calc_sig_R(U, I, sig_I) </code>. Why does the function <code> def calc_sig_R(U, I, sig_I) </code> not have the uncertainty of the voltage as an input variable? Note that the propagated uncertainty must always be rounded up." + "First add the corresponding code to the functions in the cell below to calculate the resistance with the function <code> def uri(U,I) </code> and the uncertainty with the function def <code> def calc_sig_R(U, I, sig_I) </code>. Why does the function <code> def calc_sig_R(U, I, sig_I) </code> not have the uncertainty of the voltage as an input variable? " ], "metadata": { "collapsed": false } }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [], + "source": [ + "def uri(U,I):\n", + " \"\"\"\n", + " Returns the value for the resistance following Ohm's law U=R*I\n", + " :param U: voltage value\n", + " :param I: current value\n", + " :return: resistance value\n", + " \"\"\"\n", + " # Complete the code\n", + "\n", + " return \n", + "\n", + "def calc_sig_R(U, I, sig_I):\n", + " \"\"\"\n", + " Returns the value of the uncertainty of the resistance according to Ohm's law and Gaussian error propagation\n", + " :param U: voltage value\n", + " :param I: current value\n", + " :param sig_I: uncertainty of the resistance\n", + " :return: \n", + " \"\"\"\n", + " # Complete the code\n", + " return " + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:00:33.278431500Z", + "start_time": "2024-02-23T13:00:33.248408400Z" + } + } + }, { "cell_type": "markdown", "source": [ - "First add the code here to calculate the resistance with the function<code> def uri(U,I) </code> and add them to your pandas dataframe. Round the values to a suitable number of decimal places using the function [round](https://docs.python.org/3/library/functions.html#round)" + "Afterwards, add the code here to calculate the resistance with the function<code> def uri(U,I) </code> and add them to your pandas dataframe. Round the values to a suitable number of decimal places using the function [round](https://docs.python.org/3/library/functions.html#round)." ], "metadata": { "collapsed": false @@ -260,21 +189,8 @@ }, { "cell_type": "code", - "execution_count": 32, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " voltage voltage_sig current current_sig resistance resistance_sig\n", - "0 10.0 0.0 1.55 0.08 6.45 0.34\n", - "1 15.0 0.0 2.19 0.11 6.85 0.35\n", - "2 20.0 0.0 3.00 0.15 6.67 0.34\n", - "3 25.0 0.0 3.97 0.20 6.30 0.32\n", - "4 30.0 0.0 6.18 1.55 4.85 1.22\n" - ] - } - ], + "execution_count": 5, + "outputs": [], "source": [ "# Calculate and round the resistance\n", "data.loc[:, \"resistance\"] = " @@ -283,13 +199,17 @@ "collapsed": false, "pycharm": { "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-02-23T13:00:43.809786300Z", + "start_time": "2024-02-23T13:00:43.786756300Z" } } }, { "cell_type": "markdown", "source": [ - "Now calculate the uncertainty, round it and add it to the dataframe. Then print the dataframe to check your results." + "Now calculate the uncertainty, round it up and add it to the dataframe. Then print the dataframe to check your results." ], "metadata": { "collapsed": false @@ -302,6 +222,7 @@ "source": [ "# Calculate resistance uncertainty\n", "# Remember that uncertainties shall always be rounded up!\n", + "data.loc[:, \"resistance_sig\"] = \n", "\n", "### Print resulting table in one line\n", "pd.set_option(\"expand_frame_repr\", False)\n", @@ -315,7 +236,7 @@ "cell_type": "markdown", "source": [ "### Task 2e\n", - "Now we have several pairs of measured values with different measurement uncertainties. In order to combine the information including the measurement uncertainties, we need to determine a suitable estimated value for the resistance. Calculate an estimation value for the resistance first using the arithmetic mean by using the function [np.mean](https://numpy.org/doc/stable/reference/generated/numpy.mean.html) and secondly using the expression for the weighted mean. The weighted mean is defined by the following formula, which you must add under the function <code> def weighted_mean(x, sig_x) </code>:\n", + "Now we have several pairs of measured values with different measurement uncertainties. In order to combine the information including the measurement uncertainties, we need to determine a suitable estimated value for the resistance. Calculate an estimation value for the resistance first using the arithmetic mean by using the function [np.mean](https://numpy.org/doc/stable/reference/generated/numpy.mean.html) and secondly using the expression for the weighted mean. The weighted mean is defined by the following formula, which you must add under the function <code> def weighted_mean(x, sig_x) </code> in the cell below:\n", "\n", "\n", "\n", @@ -338,18 +259,40 @@ }, { "cell_type": "code", - "execution_count": 33, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " weighted arithmetic\n", - "mean 6.52 6.22\n", - "uncertainty 0.17 0.72\n" - ] - } + "execution_count": 7, + "outputs": [], + "source": [ + "def weighted_mean(x, sig_x):\n", + " \"\"\"\n", + " Returns the weighted mean of variables x and their uncertainties sig_x\n", + " :param x: array with x values\n", + " :param sig_x: array with uncertainty of respective x value\n", + " :return: weighted mean\n", + " \"\"\"\n", + "\n", + " return \n", + "\n", + "def sig_weighted_mean(sig_x):\n", + " \"\"\"\n", + " Returns the uncertainty of the weighted mean of variables x and their uncertainties sig_x\n", + " :param sig_x: array with uncertainty of respective x value\n", + " :return: uncertainty of weighted mean\n", + " \"\"\"\n", + "\n", + " return " ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:01:31.910988Z", + "start_time": "2024-02-23T13:01:31.900940200Z" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], "source": [ "# Extract the needed data from our dataframe\n", "\n", @@ -386,7 +329,7 @@ "\n", "$m = \\frac{\\sum_{i=1}^N \\frac{x_i \\cdot y_i}{\\sigma_i^2}}{\\sum_{i=1}^N \\frac{ x_i^2}{\\sigma_i^2}}$\n", "\n", - "In this case, $x = U$, $y = I$ and $\\sigma_y = \\sigma_I$. Add the function <code> def ml_estimator(x, y, sig_y) </code> to the function cell and determine both the value for the ML estimator $m$ and then the value for the resistance. Round the value for the resistance to a meaningful number of decimal places and compare the value for the resistance with the previous ones. \n" + "In this case, $x = U$, $y = I$ and $\\sigma_y = \\sigma_I$. Add the function <code> def ml_estimator(x, y, sig_y) </code> to the cell below and determine both the value for the ML estimator $m$ and then the value for the resistance. Round the value for the resistance to a meaningful number of decimal places and compare the value for the resistance with the previous ones. \n" ], "metadata": { "collapsed": false, @@ -397,19 +340,32 @@ }, { "cell_type": "code", - "execution_count": 34, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "m = 0.152\n", - "\n", - " weighted arithmetic ML-method\n", - "0 6.52 6.22 6.58\n" - ] - } + "execution_count": 9, + "outputs": [], + "source": [ + "def ml_estimator(x, y, sig_y):\n", + " \"\"\"\n", + " Returns the parameter m that is determined by using the maximum likelihood method.\n", + " :param x:\n", + " :param y:\n", + " :param sigma:\n", + " :return: m\n", + " \"\"\"\n", + "\n", + " return " ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:01:40.086529600Z", + "start_time": "2024-02-23T13:01:40.070463800Z" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], "source": [ "# Extract needed data from dataframe\n", "x = \n", @@ -438,8 +394,7 @@ "### Task 2g\n", "\n", "In practice, the majority of functional relationships can no longer be determined analytically using the ML method. For these cases, the Python package [Scipy](https://scipy.org/) can be used. The [scipy.optimize.curve_fit](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html) function can be used to estimate the parameters of previously defined functional relationships for a specific data set. In the scipy documentation you will find all relevant information and steps for the implementation. \n", - "Use the function to fit a linear relationship to the measurement data according to task 2f). Compare the result for the resistance with the previous ones. \n", - "\n" + "Use the function to fit a linear relationship to the measurement data according to task 2f). Compare the result for the resistance with the previous ones. " ], "metadata": { "collapsed": false, @@ -481,7 +436,7 @@ "\n", "$\\chi^2 = \\sum_{i=1}^N \\frac{(y_i - f(x_i, m))^2}{\\sigma_i^2}$\n", "\n", - "Where $x=U$, $y=I$, $\\sigma_i = \\sigma_y_i$ and $f(x_i,m) = U_i/R$. Complete the function <code> def chi2_formula(x, y, sig_y, R) </code> and calculate the $\\Chi^2/n_{d.o.f.}$ for the results from tasks 2f and 2g. Explain what the numerical values for $\\Chi^2/n_{d.o.f.}$ mean.\n", + "Where $x=U$, $y=I$, $\\sigma_i = \\sigma_y_i$ and $f(x_i,m) = U_i/R$. Complete the function <code> def chi2_formula(x, y, sig_y, R) </code> in the cell below and calculate the $\\Chi^2/n_{d.o.f.}$ for the results from 2e) (arithmetic and weighted mean) and 2g) (Scipy Curve-Fit). Explain what the numerical values for $\\Chi^2/n_{d.o.f.}$ mean.\n", "\n" ], "metadata": { @@ -490,7 +445,32 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 14, + "outputs": [], + "source": [ + "def chi2_formula(x, y, sig_y, R):\n", + " \"\"\"\n", + " Formula to calculate the Chi^2 value in the case of the relationship y = x/R\n", + " :param x: x values\n", + " :param y: y values\n", + " :param sig_y: uncertainty of y values\n", + " :param m: slope\n", + " :return: \n", + " \"\"\"\n", + "\n", + " return " + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:07:01.068534900Z", + "start_time": "2024-02-23T13:07:01.050115Z" + } + } + }, + { + "cell_type": "code", + "execution_count": null, "outputs": [], "source": [ "# Determine n_dof\n", @@ -504,8 +484,10 @@ "\n", "\n", "# Print the resulting Chi^2/ndof\n", - "print(\"Chi^2/ndof (ML-Method) = \" + str(round(chi2_ml_n), 4))\n", - "print(\"Chi^2/ndof (Scipy) = \" + str(round(chi2_sc_n), 4))" + "# Print the resulting Chi^2/ndof\n", + "print(\"Chi^2/ndof (Airthmetic Mean) = \" + str(round(chi2_ar_n, 4)))\n", + "print(\"Chi^2/ndof (Weighted Mean) = \" + str(round(chi2_weigh_n, 4)))\n", + "print(\"Chi^2/ndof (Scipy) = \" + str(round(chi2_sc_n, 4)))\n" ], "metadata": { "collapsed": false, -- GitLab From f5b37a9dcfb536233a4de417a3f1a4b006001563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sen?= <oemer.sen@rwth-aachen.de> Date: Wed, 8 May 2024 17:37:53 +0200 Subject: [PATCH 06/23] deleted errror output --- ...Ex2_Battery_Optimization_noSolutions.ipynb | 48 +++---------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb index 5a059e6..1fa5952 100644 --- a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb +++ b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb @@ -54,7 +54,7 @@ "cell_type": "markdown", "source": [ "# Task 2 a)\n", - "Plot the electrical demand, the electricity price as well as the PV generation for a 8 kWp plant. Use the python library matplotlib." + "Plot the electrical demand, the electricity price as well as the PV generation for a 8 kWp plant. Use the python library matplotlib. You can find a user guide under the following [link](https://matplotlib.org/stable/users/index)." ], "metadata": { "collapsed": false @@ -94,7 +94,7 @@ "cell_type": "markdown", "source": [ "# Task 2 b)\n", - "Calculate the costs of electricity supply assuming the PV plant and battery storage system are not operating. (Using numpy might be helpfull)" + "Calculate the costs of electricity supply assuming the PV plant and battery storage system are not operating. (Using numpy might be helpfull. You can find a user guide under the following [link](https://numpy.org/doc/stable/).)" ], "metadata": { "collapsed": false @@ -159,19 +159,7 @@ { "cell_type": "code", "execution_count": 1, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'get_total_costs' is not defined", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mNameError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[1;32mIn[1], line 5\u001B[0m\n\u001B[0;32m 2\u001B[0m residuum_kW \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;66;03m# !!! <-- insert calculation\u001B[39;00m\n\u001B[0;32m 4\u001B[0m \u001B[38;5;66;03m# call cost calculating function\u001B[39;00m\n\u001B[1;32m----> 5\u001B[0m c_total_residuum \u001B[38;5;241m=\u001B[39m \u001B[43mget_total_costs\u001B[49m(residuum_kW, c_euro_kWh)\n\u001B[0;32m 6\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mThe total electricity costs are \u001B[39m\u001B[38;5;132;01m{\u001B[39;00m\u001B[38;5;28mround\u001B[39m(c_total_residuum,\u001B[38;5;241m2\u001B[39m)\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m €\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n", - "\u001B[1;31mNameError\u001B[0m: name 'get_total_costs' is not defined" - ] - } - ], + "outputs": [], "source": [ "# calculate residuum\n", "residuum_kW = 0 # !!! <-- insert calculation\n", @@ -203,7 +191,7 @@ "cell_type": "markdown", "source": [ "# Task 2d)\n", - "In the following, an optimization problem is set up to optimize the operation of the battery in such a way that the electricity supply for the house is as cost-effective as possible." + "In the following, an optimization problem is set up to optimize the operation of the battery in such a way that the electricity supply for the house is as cost-effective as possible. " ], "metadata": { "collapsed": false @@ -272,16 +260,7 @@ { "cell_type": "code", "execution_count": 6, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The total electricity costs are 0 €\n", - "The total electricity costs are 0.55 €\n" - ] - } - ], + "outputs": [], "source": [ "## call the optimization function\n", "model, buy, soc, feedin_cost_minimizing = optimze_battery_operation(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh)\n", @@ -333,7 +312,7 @@ "cell_type": "markdown", "source": [ "# Task 2 e)\n", - "Change the battery optimization function (1 Variable, 1 Objective, 1 Constraint) below so that the maximium (single peak value, not sum of all values!) feed in from the pv plant to the grid gets minimized. How much was the maximum feed in without battery operation, with cost minimizing battery operation and with feed-in minimizing battery operation? Plot the resulting feed-in time series." + "Change the battery optimization function (1 Variable, 1 Objective, 1 Constraint) below so that the maximium (single peak value, not sum of all values!) feed in from the pv plant to the grid gets minimized. How much was the maximum feed in without battery operation, with cost minimizing battery operation and with feed-in minimizing battery operation? Plot the resulting feed-in time series. You can take a look at the user guide of the library Pulp under the following [link](https://coin-or.github.io/pulp/main/includeme.html)." ], "metadata": { "collapsed": false @@ -343,20 +322,7 @@ { "cell_type": "code", "execution_count": 7, - "outputs": [ - { - "ename": "TypeError", - "evalue": "'int' object is not subscriptable", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[1;32mIn[7], line 48\u001B[0m\n\u001B[0;32m 45\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m model, buy, soc, feedin\n\u001B[0;32m 47\u001B[0m \u001B[38;5;66;03m# call optimization function\u001B[39;00m\n\u001B[1;32m---> 48\u001B[0m model, buy, soc, feedin \u001B[38;5;241m=\u001B[39m \u001B[43moptimze_battery_operation_PV\u001B[49m\u001B[43m(\u001B[49m\u001B[43mel_demand_kW\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpv_kWp\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpv_pu\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mE_bat_kWh\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mP_bat_max_charge_kW\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mP_bat_max_discharge_kW\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mc_euro_kWh\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m 50\u001B[0m \u001B[38;5;66;03m# read results\u001B[39;00m\n\u001B[0;32m 51\u001B[0m feedin_results \u001B[38;5;241m=\u001B[39m []\n", - "Cell \u001B[1;32mIn[7], line 40\u001B[0m, in \u001B[0;36moptimze_battery_operation_PV\u001B[1;34m(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh)\u001B[0m\n\u001B[0;32m 38\u001B[0m \u001B[38;5;66;03m# !!! insert new constraint\u001B[39;00m\n\u001B[0;32m 39\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m t \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mrange\u001B[39m(\u001B[38;5;241m23\u001B[39m):\n\u001B[1;32m---> 40\u001B[0m model \u001B[38;5;241m+\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[43mmax_pv_feed_in\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m]\u001B[49m \u001B[38;5;241m>\u001B[39m\u001B[38;5;241m=\u001B[39m feedin[t]\n\u001B[0;32m 42\u001B[0m \u001B[38;5;66;03m# Solve the optimization problem\u001B[39;00m\n\u001B[0;32m 43\u001B[0m model\u001B[38;5;241m.\u001B[39msolve()\n", - "\u001B[1;31mTypeError\u001B[0m: 'int' object is not subscriptable" - ] - } - ], + "outputs": [], "source": [ "# Import of necessary packages\n", "from pulp import LpProblem, LpVariable, lpSum, LpMinimize\n", -- GitLab From f4ce3662fe3c73f67a2a7e539482397de360edd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sen?= <oemer.sen@rwth-aachen.de> Date: Wed, 8 May 2024 17:47:46 +0200 Subject: [PATCH 07/23] fixed pulp import error --- Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb index 1fa5952..d4b9b19 100644 --- a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb +++ b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb @@ -203,6 +203,9 @@ "execution_count": 5, "outputs": [], "source": [ + "import sys", + "!{sys.executable} -m pip install pulp", + "\n", "# Import of necessary packages\n", "from pulp import LpProblem, LpVariable, lpSum, LpMinimize\n", "\n", -- GitLab From e2488233cda03614d43b3b628d8b7721735977ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sen?= <oemer.sen@rwth-aachen.de> Date: Wed, 8 May 2024 17:48:40 +0200 Subject: [PATCH 08/23] added new space --- Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb index d4b9b19..ef56481 100644 --- a/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb +++ b/Excercise_1/Ex2_Battery_Optimization_noSolutions.ipynb @@ -203,8 +203,8 @@ "execution_count": 5, "outputs": [], "source": [ - "import sys", - "!{sys.executable} -m pip install pulp", + "import sys\n", + "!{sys.executable} -m pip install pulp\n", "\n", "# Import of necessary packages\n", "from pulp import LpProblem, LpVariable, lpSum, LpMinimize\n", -- GitLab From afb5d2ac46ae07b40558a7a6dd6ee798254bae8d Mon Sep 17 00:00:00 2001 From: Julius Zocher <julius.zocher@rwth-aachen.de> Date: Mon, 13 May 2024 18:18:01 +0200 Subject: [PATCH 09/23] Update environment.yml --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index b1936a1..596dacf 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,4 @@ -name: DEV +name: base channels: - conda-forge dependencies: -- GitLab From 0c837200f93ae5905585ec57b2dec5854687632c Mon Sep 17 00:00:00 2001 From: Franziska Maria Tischbein <franziska.tischbein@rwth-aachen.de> Date: Thu, 16 May 2024 11:47:34 +0200 Subject: [PATCH 10/23] Upload Solution Exercise 2 - Measurement and Sensor Technology --- Excercise_2/2024_02_23_DEV_UE2_A2_v2.ipynb | 729 +++++++++++++++++++++ 1 file changed, 729 insertions(+) create mode 100644 Excercise_2/2024_02_23_DEV_UE2_A2_v2.ipynb diff --git a/Excercise_2/2024_02_23_DEV_UE2_A2_v2.ipynb b/Excercise_2/2024_02_23_DEV_UE2_A2_v2.ipynb new file mode 100644 index 0000000..deb8b6f --- /dev/null +++ b/Excercise_2/2024_02_23_DEV_UE2_A2_v2.ipynb @@ -0,0 +1,729 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# DEV Exercise 2" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "This Jupyter notebook contains tasks that are calculated for you on the blackboard during the exercise session. To practice using python and to see the advantage of programming when dealing with data, you will reprogram parts of it in this Jupyter notebook. If you have not yet installed the packages required for this exercise, run the following cell to install them." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 1, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: pandas in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (2.0.3)\n", + "Requirement already satisfied: numpy>=1.20.3 in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from pandas) (1.24.4)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from pandas) (2.8.2)\n", + "Requirement already satisfied: pytz>=2020.1 in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from pandas) (2023.4)\n", + "Requirement already satisfied: tzdata>=2022.1 in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from pandas) (2023.4)\n", + "Requirement already satisfied: six>=1.5 in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: You are using pip version 21.1.1; however, version 24.0 is available.\n", + "You should consider upgrading via the 'c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\python.exe -m pip install --upgrade pip' command.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: numpy in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (1.24.4)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: You are using pip version 21.1.1; however, version 24.0 is available.\n", + "You should consider upgrading via the 'c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\python.exe -m pip install --upgrade pip' command.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: scipy in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (1.10.1)\n", + "Requirement already satisfied: numpy<1.27.0,>=1.19.5 in c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from scipy) (1.24.4)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: You are using pip version 21.1.1; however, version 24.0 is available.\n", + "You should consider upgrading via the 'c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\python.exe -m pip install --upgrade pip' command.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting openpyxl\n", + " Using cached openpyxl-3.1.2-py2.py3-none-any.whl (249 kB)\n", + "Collecting et-xmlfile\n", + " Using cached et_xmlfile-1.1.0-py3-none-any.whl (4.7 kB)\n", + "Installing collected packages: et-xmlfile, openpyxl\n", + "Successfully installed et-xmlfile-1.1.0 openpyxl-3.1.2\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: You are using pip version 21.1.1; however, version 24.0 is available.\n", + "You should consider upgrading via the 'c:\\users\\f.tischbein\\appdata\\local\\programs\\python\\python38\\python.exe -m pip install --upgrade pip' command.\n" + ] + } + ], + "source": [ + "!pip install pandas\n", + "!pip install numpy\n", + "!pip install scipy\n", + "!pip install openpyxl" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T12:58:13.139796300Z", + "start_time": "2024-02-23T12:57:57.909215100Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Now run the following cell to import the most important libraries. You can run a cell either by clicking `Run` on the toolbar or by pressing `CTRL+RETURN`." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-02-23T12:58:40.909857800Z", + "start_time": "2024-02-23T12:58:28.941463400Z" + } + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import numpy as np\n", + "from scipy.optimize import curve_fit" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Predefine functions\n", + "It is good programming practice to define functions at the beginning that you want to use again and again in the course of the code. You can find instructions with examples for defining functions under the following [link](https://www.w3schools.com/python/python_functions.asp). For reasons of overview, however, we will always define these in the respective task section first. As an example, we give you the function <code> round_up(x, decimals) </code>. This function always rounds up values and will be used more frequently throughout the code." + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "def round_up(x, decimals: int):\n", + " \"\"\"\n", + " Returns the numerical value given in \"value\", rounded up to the given number of decimal places given in \"decimals\". This function is particularly relevant when dealing with measurement uncertainties, as these must always be rounded up.\n", + "\n", + " :param x: value to be rounded\n", + " :param decimals: number of decimals\n", + " :return: rounded up value\n", + " \"\"\"\n", + " value = np.ceil(pow(10, decimals)*x) / pow(10, decimals)\n", + "\n", + " return value" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2a\n", + "First, the measurement data must be read in from the Excel spreadsheet. The table contains the measured voltages and currents, each with their uncertainties. Use the [pd.read_excel](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html) function to do this.\n" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 3, + "outputs": [], + "source": [ + "### First, the data needs to be loaded from the given xlsx-file. Note that all datatypes shall be set to float.\n", + "\n", + "data = pd.read_excel(\"measurement_data.xlsx\", index_col=0, dtype=float)\n", + "\n", + "### Define arrays with the corresponding voltage and current values for later use.\n", + "U = data.loc[:, \"voltage\"]\n", + "sig_U = data.loc[:, \"voltage_sig\"]\n", + "I = data.loc[:, \"current\"]\n", + "sig_I = data.loc[:, \"current_sig\"]" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:00:28.694732900Z", + "start_time": "2024-02-23T13:00:28.119399700Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2b\n", + "After the data has been read in, the resistance and its uncertainty are to be determined for the value pairs. \n", + "First add the corresponding code to the functions in the cell below to calculate the resistance with the function <code> def uri(U,I) </code> and the uncertainty with the function def <code> def calc_sig_R(U, I, sig_I) </code>. Why does the function <code> def calc_sig_R(U, I, sig_I) </code> not have the uncertainty of the voltage as an input variable? " + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [], + "source": [ + "def uri(U,I):\n", + " \"\"\"\n", + " Returns the value for the resistance following Ohm's law U=R*I\n", + " :param U: voltage value\n", + " :param I: current value\n", + " :return: resistance value\n", + " \"\"\"\n", + " # Complete the code\n", + " R = U/I\n", + " return R\n", + "\n", + "def calc_sig_R(U, I, sig_I):\n", + " \"\"\"\n", + " Returns the value of the uncertainty of the resistance according to Ohm's law and Gaussian error propagation\n", + " :param U: voltage value\n", + " :param I: current value\n", + " :param sig_I: uncertainty of the resistance\n", + " :return: \n", + " \"\"\"\n", + " # Complete the code\n", + " sig_R = U/I**2 * sig_I\n", + " return sig_R" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:00:33.278431500Z", + "start_time": "2024-02-23T13:00:33.248408400Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Afterwards, add the code here to calculate the resistance with the function<code> def uri(U,I) </code> and add them to your pandas dataframe. Round the values to a suitable number of decimal places using the function [round](https://docs.python.org/3/library/functions.html#round)." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": [ + "# Calculate and round the resistance\n", + "data.loc[:, \"resistance\"] = round( uri(U,I) , 2)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-02-23T13:00:43.809786300Z", + "start_time": "2024-02-23T13:00:43.786756300Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Now calculate the uncertainty, round it up and add it to the dataframe. Then print the dataframe to check your results." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 6, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " voltage voltage_sig current current_sig resistance resistance_sig\n", + "0 10.0 0.0 1.55 0.08 6.45 0.34\n", + "1 15.0 0.0 2.19 0.11 6.85 0.35\n", + "2 20.0 0.0 3.00 0.15 6.67 0.34\n", + "3 25.0 0.0 3.97 0.20 6.30 0.32\n", + "4 30.0 0.0 6.18 1.55 4.85 1.22\n" + ] + } + ], + "source": [ + "# Calculate resistance uncertainty\n", + "# Remember that uncertainties shall always be rounded up!\n", + "data.loc[:, \"resistance_sig\"] = round_up( calc_sig_R(U, I, sig_I), 2)\n", + "\n", + "### Print resulting table in one line\n", + "pd.set_option(\"expand_frame_repr\", False)\n", + "print(data)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:00:55.126280100Z", + "start_time": "2024-02-23T13:00:55.105678900Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2e\n", + "Now we have several pairs of measured values with different measurement uncertainties. In order to combine the information including the measurement uncertainties, we need to determine a suitable estimated value for the resistance. Calculate an estimation value for the resistance first using the arithmetic mean by using the function [np.mean](https://numpy.org/doc/stable/reference/generated/numpy.mean.html) and secondly using the expression for the weighted mean. The weighted mean is defined by the following formula, which you must add under the function <code> def weighted_mean(x, sig_x) </code> in the cell below:\n", + "\n", + "\n", + "\n", + "$\\left<x\\right>=\\frac{\\sum_{i=1}^N x_i / \\sigma_{i,abs}^2}{\\sum_{i=1}^N 1 / \\sigma_{i,abs}^2}$\n", + "\n", + "\n", + "Also calculate the uncertainty of the calculated mean values, in each case using the function [np.std](https://numpy.org/doc/stable/reference/generated/numpy.std.html) for the arithmetic mean and the function <code> def sig_weighted_mean(sig_x) </code> for the weighted mean. In advance, add the following formula to the function <code> def sig_weighted_mean(sig_x) </code> using [np.sqrt](https://numpy.org/doc/stable/reference/generated/numpy.sqrt.html):\n", + "\n", + "$\\sigma_{\\left<x\\right>}=\\frac{1}{\\sqrt{\\sum_{i=1}^N 1 / \\sigma_{i,abs}^2}}$\n", + "\n", + "Remember to round the values to a meaningful number of decimal places using [round](https://docs.python.org/3/library/functions.html#round) and <code> def round_up(x, decimals) </code>. \n", + "Compare your results and explain where the differences come from! \n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 7, + "outputs": [], + "source": [ + "def weighted_mean(x, sig_x):\n", + " \"\"\"\n", + " Returns the weighted mean of variables x and their uncertainties sig_x\n", + " :param x: array with x values\n", + " :param sig_x: array with uncertainty of respective x value\n", + " :return: weighted mean\n", + " \"\"\"\n", + " nen = 0\n", + " zae = 0\n", + " for i in range(len(x)):\n", + " nen += x[i]/sig_x[i]**2\n", + " zae += 1/sig_x[i]**2\n", + " \n", + " wm = nen/zae\n", + " return wm\n", + "\n", + "def sig_weighted_mean(sig_x):\n", + " \"\"\"\n", + " Returns the uncertainty of the weighted mean of variables x and their uncertainties sig_x\n", + " :param sig_x: array with uncertainty of respective x value\n", + " :return: uncertainty of weighted mean\n", + " \"\"\"\n", + " sum_weights = 0\n", + " for i in range(len(sig_x)):\n", + " sum_weights += 1/sig_x[i]**2\n", + " \n", + " sig_wm = 1/np.sqrt(sum_weights)\n", + " return sig_wm" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:01:31.910988Z", + "start_time": "2024-02-23T13:01:31.900940200Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 8, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Weighted Arithmetic\n", + "Mean 6.52 6.22\n", + "Uncertainty 0.17 0.72\n" + ] + } + ], + "source": [ + "# Extract the needed data from our dataframe\n", + "\n", + "n = data.shape[0] # number of measurements\n", + "R = data.loc[:, \"resistance\"]\n", + "sig_R = data.loc[:, \"resistance_sig\"]\n", + "\n", + "# Calculate the arithmetic mean and its uncertainty and round your results\n", + "ar_mean = round(np.mean(R), 2)\n", + "sig_ar_mean = round_up(np.std(R), 2)\n", + "\n", + "# Calculate the weighted mean and its uncertainty and round your results\n", + "w_mean = round( weighted_mean(R, sig_R), 2)\n", + "sig_w_mean = round_up(sig_weighted_mean(sig_R), 2)\n", + "\n", + "# Create and print a Dataframe with results\n", + "results_2e = pd.DataFrame(np.array([[ w_mean, ar_mean], [ sig_w_mean, sig_ar_mean ]]), columns=[\"Weighted\", \"Arithmetic\"], index=[\"Mean\", \"Uncertainty\"])\n", + "print(results_2e)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-02-23T13:01:34.538085900Z", + "start_time": "2024-02-23T13:01:34.513089800Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2f\n", + "\n", + "In the lecture and the first part of this exercise session, we learned about the maximum likelihood method on the one hand and solved the analytical solution of the problem here using the ML method on the other.\n", + "According to Ohm's law, $I = U/R = m*U$ with $m=1/R$. This results in a linear relationship between the current and the voltage. Using the ML method, we have calculated that the following equation applies for m:\n", + "\n", + "$m = \\frac{\\sum_{i=1}^N \\frac{x_i \\cdot y_i}{\\sigma_i^2}}{\\sum_{i=1}^N \\frac{ x_i^2}{\\sigma_i^2}}$\n", + "\n", + "In this case, $x = U$, $y = I$ and $\\sigma_y = \\sigma_I$. Add the function <code> def ml_estimator(x, y, sig_y) </code> to the cell below and determine both the value for the ML estimator $m$ and then the value for the resistance. Round the value for the resistance to a meaningful number of decimal places and compare the value for the resistance with the previous ones. \n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 9, + "outputs": [], + "source": [ + "def ml_estimator(x, y, sig_y):\n", + " \"\"\"\n", + " Returns the parameter m that is determined by using the maximum likelihood method.\n", + " :param x:\n", + " :param y:\n", + " :param sigma:\n", + " :return: m\n", + " \"\"\"\n", + " nen = 0\n", + " zae = 0\n", + " for i in range(len(x)):\n", + " nen += (x[i]*y[i]/sig_y[i]**2)\n", + " zae += (x[i]/sig_y[i])**2\n", + " m = nen/zae\n", + " return m" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:01:40.086529600Z", + "start_time": "2024-02-23T13:01:40.070463800Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 10, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m = 0.15238572230070688\n", + "\n", + " weighted arithmetic ML-method\n", + "0 6.52 6.22 6.56\n" + ] + } + ], + "source": [ + "# Extract needed data from dataframe\n", + "x = data.loc[:, \"voltage\"]\n", + "y = data.loc[:, \"current\"]\n", + "sig_y = data.loc[:, \"current_sig\"]\n", + "\n", + "# Calculate best estimate for the parameter m\n", + "m = ml_estimator(x, y, sig_y)\n", + "R_ml = 1/m\n", + "R_ml = round(R_ml, 2)\n", + "print(\"m = \" + str(m) + \"\\n\")\n", + "\n", + "# Create and print a Dataframe with results\n", + "results_2f = pd.DataFrame(np.array([[w_mean, ar_mean, R_ml]]), columns=[\"weighted\", \"arithmetic\", \"ML-method\"])\n", + "print(results_2f)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-02-23T13:01:42.678661600Z", + "start_time": "2024-02-23T13:01:42.649206600Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2g\n", + "\n", + "In practice, the majority of functional relationships can no longer be determined analytically using the ML method. For these cases, the Python package [Scipy](https://scipy.org/) can be used. The [scipy.optimize.curve_fit](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html) function can be used to estimate the parameters of previously defined functional relationships for a specific data set. In the scipy documentation you will find all relevant information and steps for the implementation. \n", + "Use the function to fit a linear relationship to the measurement data according to task 2f). Compare the result for the resistance with the previous ones. \n", + "\n" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 11, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Parameter m = 0.15\n", + "Uncertainty = 0.0031424538988126835\n", + " weighted arithmetic ML-method Scipy Curve-Fit\n", + "0 6.52 6.22 6.56 6.56\n" + ] + } + ], + "source": [ + "# First, the linear relationship needs to be defined as a function\n", + "def linear(x, a):\n", + " \"\"\"\n", + " Linear relationship between y=m*x and x\n", + " :param x: x Variables\n", + " :param a: Slope\n", + " :return: y\n", + " \"\"\"\n", + " return x*a\n", + "\n", + "def sig_R_m(m, sig_m):\n", + " \"\"\"\n", + " Gaussian Error Distribution to calculate the uncertainty of R=1/m\n", + " :param m: slope\n", + " :param sig_m: uncertainty of the slope\n", + " :return: uncertainty of the resistance\n", + " \"\"\"\n", + " sig_R = sig_m/m**2\n", + " return sig_R\n", + " \n", + "\n", + "# Use curve_fit to solve the problem and print the parameter m with its uncertainty\n", + "popt, pcov = curve_fit(linear, U, I, sigma=sig_I)\n", + "m = popt[0]\n", + "sig_m = np.sqrt(pcov[0,0])\n", + "print(\"Optimal Parameter m = \" + str(round(m, 2)))\n", + "print(\"Uncertainty = \" + str(sig_m))\n", + "\n", + "# Calculate the resistance and its uncertainty (Hint: Think about Gaussian Error Propagation!)\n", + "R_sc = round(1/m, 2)\n", + "sig_sc = round_up(sig_R_m(m, sig_m),2)\n", + "\n", + "\n", + "# Create and print a Dataframe with results\n", + "results_2g = pd.DataFrame(np.array([[w_mean, ar_mean, R_ml, R_sc]]), columns=[\"weighted\", \"arithmetic\", \"ML-method\", \"Scipy Curve-Fit\"])\n", + "print(results_2g)\n" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:01:47.668723700Z", + "start_time": "2024-02-23T13:01:47.652728400Z" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2h\n", + "\n", + "The $\\Chi^2$ test, which is defined as follows, is suitable for determining the quality of the fit:\n", + "\n", + "$\\chi^2 = \\sum_{i=1}^N \\frac{(y_i - f(x_i, m))^2}{\\sigma_i^2}$\n", + "\n", + "Where $x=U$, $y=I$, $\\sigma_i = \\sigma_y_i$ and $f(x_i,m) = U_i/R$. Complete the function <code> def chi2_formula(x, y, sig_y, R) </code> in the cell below and calculate the $\\Chi^2/n_{d.o.f.}$ for the results from 2e) (arithmetic and weighted mean) and 2g) (Scipy Curve-Fit). Explain what the numerical values for $\\Chi^2/n_{d.o.f.}$ mean.\n", + "\n" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 14, + "outputs": [], + "source": [ + "def chi2_formula(x, y, sig_y, R):\n", + " \"\"\"\n", + " Formula to calculate the Chi^2 value in the case of the relationship y = x/R\n", + " :param x: x values\n", + " :param y: y values\n", + " :param sig_y: uncertainty of y values\n", + " :param m: slope\n", + " :return: \n", + " \"\"\"\n", + " chi2 = 0\n", + " for i in range(len(x)):\n", + " chi2 += (y[i] - x[i]/R)**2/sig_y[i]**2\n", + " return chi2" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-02-23T13:07:01.068534900Z", + "start_time": "2024-02-23T13:07:01.050115Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 16, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Chi^2/ndof (Airthmetic Mean) = 1.867\n", + "Chi^2/ndof (Weighted Mean) = 0.6881\n", + "Chi^2/ndof (Scipy) = 0.6715\n" + ] + } + ], + "source": [ + "# Determine n_dof\n", + "\n", + "n = 5-1 \n", + "\n", + "# Calculate the Chi^2 for task 2e arithmetic mean\n", + "chi2_ar = chi2_formula(U, I, sig_I, ar_mean)\n", + "chi2_ar_n = chi2_ar/n\n", + "\n", + "# Calculate the Chi^2 for task 2e wighted mean\n", + "chi2_weigh = chi2_formula(U, I, sig_I, w_mean)\n", + "chi2_weigh_n = chi2_weigh/n\n", + "\n", + "# Calculate the Chi^2 for task 2g\n", + "chi2_sc = chi2_formula(U, I, sig_I, R_sc)\n", + "chi2_sc_n = chi2_sc/n\n", + "\n", + "# Print the resulting Chi^2/ndof\n", + "print(\"Chi^2/ndof (Airthmetic Mean) = \" + str(round(chi2_ar_n, 4)))\n", + "print(\"Chi^2/ndof (Weighted Mean) = \" + str(round(chi2_weigh_n, 4)))\n", + "print(\"Chi^2/ndof (Scipy) = \" + str(round(chi2_sc_n, 4)))\n", + "print(\"Chi^2/ndof < 1 means, that the uncertainties are overestimated while Chi^2/ndof > 1, means that the uncertainties are underestimated. A fit good to the data would be Chi^2/ndof = 1\")" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-02-23T13:07:55.840103800Z", + "start_time": "2024-02-23T13:07:55.707676300Z" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} -- GitLab From 643e97c3a3fbfca1f92b54db271bed02e15e07d8 Mon Sep 17 00:00:00 2001 From: "f.tischbein" <f.tischbein@iaew.rwth-aachen.de> Date: Mon, 3 Jun 2024 16:31:05 +0200 Subject: [PATCH 11/23] Add Exercise for Asset Management --- Exercise_4/2024_06_03_A6_v1_students.ipynb | 401 +++++++++++++++++++++ Exercise_4/std_type_costs.xlsx | Bin 0 -> 7861 bytes 2 files changed, 401 insertions(+) create mode 100644 Exercise_4/2024_06_03_A6_v1_students.ipynb create mode 100644 Exercise_4/std_type_costs.xlsx diff --git a/Exercise_4/2024_06_03_A6_v1_students.ipynb b/Exercise_4/2024_06_03_A6_v1_students.ipynb new file mode 100644 index 0000000..95c1b97 --- /dev/null +++ b/Exercise_4/2024_06_03_A6_v1_students.ipynb @@ -0,0 +1,401 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# DEV Exercise 6\n", + "In this Jupyter notebook we will deal with the calculation of investment and operational costs. If you have not yet installed the packages required for this exercise, run the following cell to install them." + ], + "metadata": { + "collapsed": false + }, + "id": "72ab3cf5505dbbc2" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "!pip install pandas\n", + "!pip install pandapower\n", + "!pip install simbench" + ], + "metadata": { + "collapsed": false + }, + "id": "e99cc0f65671eb71" + }, + { + "cell_type": "markdown", + "source": [ + "Now run the following cell to import the most important libraries. You can run a cell either by clicking Run on the toolbar or by pressing CTRL+RETURN." + ], + "metadata": { + "collapsed": false + }, + "id": "ddeb3acb51e3e4cd" + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-06-03T14:20:24.081312800Z", + "start_time": "2024-06-03T14:20:24.064701400Z" + } + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.simplefilter(action='ignore', category=FutureWarning)\n", + "\n", + "import pandas as pd\n", + "pd.options.display.max_rows = 10\n", + "\n", + "import pandapower as pp\n", + "import simbench as sb" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Example grid\n", + "\n", + "We will carry out the calculation using a [SimBench](https://simbench.readthedocs.io/en/stable/) example grid. SimBench is a database with synthetic grid data that maps different grid structures in low voltage. Import the grid “1-LV-rural1--0-sw” and print its properties (number and type of assets). The standard types in particular are required later for the calculation of annuities. \n" + ], + "metadata": { + "collapsed": false + }, + "id": "4963cb76c621b1bc" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "ce2565ab7f9d932b" + }, + { + "cell_type": "markdown", + "source": [ + "Afterwards, you can plot the SimBench grid by using [the pandapower simple plotting tool](https://pandapower.readthedocs.io/en/v2.0.1/plotting/matplotlib/simple_plot.html)." + ], + "metadata": { + "collapsed": false + }, + "id": "f25c7b3b43552621" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "2eb6d9517e99be23" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2a \n", + "\n", + "To calculate the annuities, we must first determine the investment costs of the lines and transformer types. For this purpose, read these from the Excel table using [the pandas function \"read_excel\"](https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html)." + ], + "metadata": { + "collapsed": false + }, + "id": "e43234c36ca7e4ba" + }, + { + "cell_type": "code", + "execution_count": 8, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:21:58.923764700Z", + "start_time": "2024-06-03T14:21:58.809907500Z" + } + }, + "id": "c6f5410eee07a074" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2b\n", + "Calculate the total investment cost in t=0 for the transformer and the lines.\n", + "For the equipment with unit prices the total costs can be calculated via\n", + "$C_{inv} = \\sum_{pc=1}^{n} {C_{pc}} = n \\cdot C_{pc}$" + ], + "metadata": { + "collapsed": false + }, + "id": "90aeb0e3ed2ee0d4" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "527eba7f1fdd1827" + }, + { + "cell_type": "markdown", + "source": [ + "For the equipment with length related costs:\n", + "$C_{inv} = \\sum_{pc=1}^{n} {l_{pc} \\cdot C_l} = (\\sum_{pc=1}^{n} {l_{pc}}) \\cdot C_l$.\n", + "First sum up over the total line length using [pandas groupby](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html)." + ], + "metadata": { + "collapsed": false + }, + "id": "de5e30b6e28016b7" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "4731e97d3b9e66f1" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "3e4b323df9b033ec" + }, + { + "cell_type": "markdown", + "source": [ + "Afterwards, calculate the total investment cost of the grid by:\n", + "$C_{grid,inv} = \\sum_{equip.} {C_{inv,equip.}}$" + ], + "metadata": { + "collapsed": false + }, + "id": "1262245f8ee4319d" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "f56701e0558fd50e" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2c\n", + "Calculate the annuity factors for the different lifetimes and components.\n", + "The annuity factors for the different lifetimes can be calculated via:\n", + "$a=\\frac{q^{T,max} \\cdot (q-1)}{q^{T,max}-1}$\n", + "\n", + "The lifetimes $T_{max}$ of the assets can be found in the Excel tables or data frames. First, define a function to calculate the annuity. This should have the lifetime and the discount rate $q = 1+r$ as input data. Usually, distribution grid operators assume an interest rate of $r=5\\%$." + ], + "metadata": { + "collapsed": false + }, + "id": "4a8f16d1e3d93bcc" + }, + { + "cell_type": "code", + "execution_count": 13, + "outputs": [], + "source": [ + "interestrate=0.05\n", + "\n", + "def annuity(n, r=interestrate):\n", + " \"\"\"Calculate the annuity factor for an asset with lifetime n years and\n", + " discount rate of r\"\"\"\n" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:21.141660Z", + "start_time": "2024-06-03T14:22:21.122542800Z" + } + }, + "id": "ba8c3aebb2b2edf1" + }, + { + "cell_type": "markdown", + "source": [ + "The following annuity costs then result for the components:" + ], + "metadata": { + "collapsed": false + }, + "id": "8bc1eeef24887502" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "e63a003d70957a59" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "966f8b18dc754e17" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2d\n", + "Afterwards, calculate the operating costs for the transformer and the lines. The operating costs can be found in the corresponding Excel files or data frames. The operating costs correspond to the multiplication of the investment costs with the specific operating costs from the Excel table or data frame." + ], + "metadata": { + "collapsed": false + }, + "id": "6e9b5e1600f9bf78" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "644d4a2306910ee6" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "1faf1a9504e028da" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2e\n", + "Calculate the annual cost of the grid equipment (sum of operating and investment costs)." + ], + "metadata": { + "collapsed": false + }, + "id": "79769693879cb833" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "de48aec2ff9058bf" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2f\n", + "In the course of digitizing the distribution grids, it is advisable to equip most of the LV system equipment with measurement technology. For our system, the following assumptions can be made:\n", + "- The specific investment costs for the measurement technology system in the transformer station is 500.000€, the interest rate equals 5%/a and its lifetime equals 20 years\n", + "- Every grid customer within our grid will also be equipped with a smart meter. As the smart meters belong to the metering point operator and not the distribution grid operator, there are no investment costs here.\n", + "- Because metering technology allows the grid to operate more efficiently, the lifetimes of all other technologies increase by 5 years\n", + "\n", + "Calculate the new annuity of investment costs for the total system with the measurement technology" + ], + "metadata": { + "collapsed": false + }, + "id": "ee9bcd85e1c42abc" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "e9bf09de56cfedb1" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2g\n", + "What are the maximum annual operating costs for the measurement equipment in order to still be cheaper than without measurement equipment?" + ], + "metadata": { + "collapsed": false + }, + "id": "51cf92fb26790ff" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "b749b6d14d16ff43" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "dfd9b25d20fc7b6c" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Exercise_4/std_type_costs.xlsx b/Exercise_4/std_type_costs.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a5491ca162bb4c77ff6db38b4bc55047e3340a2f GIT binary patch literal 7861 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 AN&o-= literal 0 HcmV?d00001 -- GitLab From f678882e392036c6b13347e71d771852ec0ca15b Mon Sep 17 00:00:00 2001 From: Markus <m.stroot@iaew.rwth-aachen.de> Date: Mon, 24 Jun 2024 16:24:53 +0200 Subject: [PATCH 12/23] Deleted outputs --- Excercise_3/Cryptography.ipynb | 189 ++++----------------------------- 1 file changed, 19 insertions(+), 170 deletions(-) diff --git a/Excercise_3/Cryptography.ipynb b/Excercise_3/Cryptography.ipynb index c575144..11f6668 100644 --- a/Excercise_3/Cryptography.ipynb +++ b/Excercise_3/Cryptography.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "595a8870", "metadata": {}, "outputs": [], @@ -41,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "caa9910f", "metadata": {}, "outputs": [], @@ -76,18 +76,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "45f1c38b-3650-4209-a288-dd5dbc004b94", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "If no error occured: everything worked as expected!\n" - ] - } - ], + "outputs": [], "source": [ "assert encode_message(\"a\", 0) == \"a\"\n", "\n", @@ -107,7 +99,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "91d2ec6b", "metadata": {}, "outputs": [], @@ -141,18 +133,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "b63b9859-0b69-447a-a39e-b5ca555d0348", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "If no error occured: everything worked as expected!\n" - ] - } - ], + "outputs": [], "source": [ "assert decode_message(\"a\", 0) == \"a\"\n", "\n", @@ -175,42 +159,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "cabfa50c-5366-4728-af0a-18791b558fac", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Key: 1: Zkxtm! Rhn yhngw max vhkkxvm dxr.\n", - "Key: 2: Yjwsl! Qgm xgmfv lzw ugjjwul cwq.\n", - "Key: 3: Xivrk! Pfl wfleu kyv tfiivtk bvp.\n", - "Key: 4: Whuqj! Oek vekdt jxu sehhusj auo.\n", - "Key: 5: Vgtpi! Ndj udjcs iwt rdggtri ztn.\n", - "Key: 6: Ufsoh! Mci tcibr hvs qcffsqh ysm.\n", - "Key: 7: Terng! Lbh sbhaq gur pbeerpg xrl.\n", - "Key: 8: Sdqmf! Kag ragzp ftq oaddqof wqk.\n", - "Key: 9: Rcple! Jzf qzfyo esp nzccpne vpj.\n", - "Key: 10: Qbokd! Iye pyexn dro mybbomd uoi.\n", - "Key: 11: Panjc! Hxd oxdwm cqn lxaanlc tnh.\n", - "Key: 12: Ozmib! Gwc nwcvl bpm kwzzmkb smg.\n", - "Key: 13: Nylha! Fvb mvbuk aol jvyylja rlf.\n", - "Key: 14: Mxkgz! Eua luatj znk iuxxkiz qke.\n", - "Key: 15: Lwjfy! Dtz ktzsi ymj htwwjhy pjd.\n", - "Key: 16: Kviex! Csy jsyrh xli gsvvigx oic.\n", - "Key: 17: Juhdw! Brx irxqg wkh fruuhfw nhb.\n", - "Key: 18: Itgcv! Aqw hqwpf vjg eqttgev mga.\n", - "Key: 19: Hsfbu! Zpv gpvoe uif dpssfdu lfz.\n", - "Key: 20: Great! You found the correct key.\n", - "Key: 21: Fqdzs! Xnt entmc sgd bnqqdbs jdx.\n", - "Key: 22: Epcyr! Wms dmslb rfc amppcar icw.\n", - "Key: 23: Dobxq! Vlr clrka qeb zloobzq hbv.\n", - "Key: 24: Cnawp! Ukq bkqjz pda yknnayp gau.\n", - "Key: 25: Bmzvo! Tjp ajpiy ocz xjmmzxo fzt.\n" - ] - } - ], + "outputs": [], "source": [ "message = \"Great! You found the correct key.\"\n", "key = random.randint(1, 25)\n", @@ -234,7 +186,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "8d4767f6", "metadata": {}, "outputs": [], @@ -289,21 +241,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "f8168f9a", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAArcAAAIpCAYAAAC48RBEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8WgzjOAAAACXBIWXMAAA9hAAAPYQGoP6dpAABZ8klEQVR4nO3deXhMd///8deQCEISFLFHLbXWTm21Ba1oaalaaqvS3rW7KdqvvbV0RSnau7aW7ujitlOtFrWVWtra961UUkGQvH9/+GVuI6EyGZKcPh/XNdeVOefMe94zc2bmNZ985ozLzEwAAACAA6RL6QYAAAAAXyHcAgAAwDEItwAAAHAMwi0AAAAcg3ALAAAAxyDcAgAAwDEItwAAAHAMwi0AAAAcg3ALAAAAxyDcAvAQFhamTp063fHrOXDggFwul2bOnOle1qlTJ2XJkuWOX3c8l8ul4cOH37Xrizd8+HC5XK67fr0p6aefflKGDBl08ODBlG7lrrnxufTtt9/K5XLp22+/TbGe7rQ78fqxc+dO+fn5afv27T6tC+ci3OIfb+bMmXK5XNq4cWOyax07dkzDhw/Xzz//nGDd3LlzNX78+GRfR1LUrVtXLpdLLpdL6dKlU1BQkO677z61b99ey5Yt89n1/Pe//02RkHg7UnNvvnD9Y3yrky/vg9GjR2vBggVJusxLL72kNm3aqFChQomur1q1qlwul6ZMmeKDDnEzO3bs0FNPPaV8+fIpICBAefPmVbt27bRjx46Ubu2mSpUqpYiICA0dOjSlW0Ea4TIzS+kmgJQ0c+ZMde7cWRs2bFDlypWTVWvjxo2qUqWKZsyYkWD0omnTptq+fbsOHDiQrOtIirp162rv3r0aM2aMJCk6Olp79uzRvHnztG/fPrVq1Uoffvih/P393ZeJiYlRunTpPJb9nR49emjy5MlKysuJmSkmJkb+/v5Knz69pGsjt59//rnOnz9/23WS09ulS5fk5+cnPz8/n13f7bh69aquXr2qjBkzJrvWsmXLdPLkSff5DRs2aOLEiXrxxRdVsmRJ9/L7779f999/f7KvT5KyZMmili1beoy638rPP/+sChUq6Mcff1T16tUTrN+9e7eKFy+usLAw5cuXT2vWrPFJnyktLCxMdevWdd9PcXFxunz5sjJkyKB06e7+2NK8efPUpk0bZc+eXV26dFHhwoV14MABvf/++zpz5ow+/vhjPfbYY8m6jhtvs68sWrRITZo00Z49e1SkSBGf1obz3N1XdAA+Ff9meauQFBwcrKeeespj2dixY9WrVy+98847CgsL07hx49zrAgIC7li/0rVgFxcXpwwZMvgk3CVHSl2/LwN1w4YNPc5nzJhREydOVMOGDVW3bl2fXEdyzZgxQwULFtQDDzyQ6PoPP/xQuXLl0htvvKGWLVvqwIEDCgsLu7tN3gXp0qVLsX1u7969at++ve6991599913ypkzp3td7969Vbt2bbVv317btm3Tvffee9M60dHRCgwMvBste7xWhIeHK1u2bJo1a5ZGjhx5V64faRfTEoDbdPToUT399NPKnTu3AgICVLp0aU2fPt29/ttvv1WVKlUkSZ07d3b/O3jmzJmqW7euFi5cqIMHD7qXX//mHRMTo2HDhqlo0aIKCAhQgQIF9MILLygmJsajB5fLpR49emjOnDkqXbq0AgICtHjx4iTflvTp02vixIkqVaqUJk2apMjISPe6G+fMXblyRSNGjFCxYsWUMWNG5ciRQ7Vq1XJPa+jUqZMmT57s7i/+JP1vXu3rr7+u8ePHq0iRIgoICNDOnTsTnXMbb9++fWrcuLECAwOVN29ejRw50mPk9WZzF2+seave4pfd+O/6LVu26OGHH1ZQUJCyZMmiBg0aaN26dR7bxE9l+eGHH9SvXz/lzJlTgYGBeuyxx3T69Om/vf8Tm3Mb/9guWLBAZcqUce9j3jy+iVm0aJFq166twMBAZc2aVRERER7/il65cqXSpUuX4F+/c+fO9Zgu4HK5FB0drVmzZrnvz7+bY7lgwQLVr1//pvOM586dq5YtW6pp06YKDg7W3LlzE2zz119/qU+fPgoLC1NAQIBy5cqlhg0bavPmzR7brV+/Xk2aNFG2bNkUGBio+++/XxMmTPDY5tdff1XLli2VPXt2ZcyYUZUrV9ZXX33lsU1SHmMz08svv6z8+fMrc+bMqlevXqL/5k9sv61bt67KlCmjnTt3ql69esqcObPy5cunV199NcHlDx48qEcffVSBgYHKlSuX+vbtqyVLltzWPN7XXntNFy5c0LvvvusRbCXpnnvu0bRp0xQdHe1xvfH76c6dO9W2bVtly5ZNtWrVStJtlqRz586pT58+KlCggAICAlS0aFGNGzdOcXFx7m1u9VohSf7+/qpbt66+/PLLW95OQGLkFrgtJ0+e1AMPPOAOIDlz5tSiRYvUpUsXRUVFqU+fPipZsqRGjhypoUOHqlu3bqpdu7YkqUaNGsqXL58iIyN15MgRvfXWW5Lk/uJUXFycHn30Ua1Zs0bdunVTyZIl9csvv+itt97S77//nmBu48qVK/Xpp5+qR48euueee7we4UqfPr3atGmjIUOGaM2aNYqIiEh0u+HDh2vMmDF65plnVLVqVUVFRWnjxo3avHmzGjZsqGeffVbHjh3TsmXL9MEHHyRaY8aMGbp06ZK6deumgIAAZc+e3eON7XqxsbF66KGH9MADD+jVV1/V4sWLNWzYMF29ejXJIza309v1duzYodq1aysoKEgvvPCC/P39NW3aNNWtW1erV69WtWrVPLbv2bOnsmXLpmHDhunAgQMaP368evTooU8++SRJfcZbs2aN5s2bp+eff15Zs2bVxIkT1aJFCx06dEg5cuTwqqYkffDBB+rYsaMaN26scePG6cKFC5oyZYpq1aqlLVu2KCwsTPXr19fzzz+vMWPGqHnz5qpYsaKOHz+unj17Kjw8XM8995y7Vvy+0K1bN0m65b+Jjx49qkOHDqlixYqJrl+/fr327NmjGTNmKEOGDHr88cc1Z84cvfjiix7bPffcc/r888/Vo0cPlSpVSmfOnNGaNWu0a9cud+1ly5apadOmypMnj3r37q3Q0FDt2rVL33zzjXr37i3p2mNcs2ZN5cuXT4MGDVJgYKA+/fRTNW/eXF988UWCf8vfzmM8dOhQvfzyy2rSpImaNGmizZs3q1GjRrp8+fJtPT5//vmnHnroIT3++ONq1aqVPv/8cw0cOFBly5bVww8/LOnaiGn9+vV1/Phx922bO3euVq1adVvX8fXXXyssLMz9unSjBx98UGFhYVq4cGGCdU888YSKFSum0aNHuz9k3u5tvnDhgurUqaOjR4/q2WefVcGCBfXjjz9q8ODBOn78eILvIST2WhGvUqVK+vLLLxUVFaWgoKDbut34hzLgH27GjBkmyTZs2HDTbbp06WJ58uSxP/74w2N569atLTg42C5cuGBmZhs2bDBJNmPGjAQ1IiIirFChQgmWf/DBB5YuXTr7/vvvPZZPnTrVJNkPP/zgXibJ0qVLZzt27Lit21anTh0rXbr0TdfPnz/fJNmECRPcywoVKmQdO3Z0ny9XrpxFRETc8nq6d+9uib2c7N+/3yRZUFCQnTp1KtF1199XHTt2NEnWs2dP97K4uDiLiIiwDBky2OnTp83MbNWqVSbJVq1a9bc1b9ab2bX7c9iwYe7zzZs3twwZMtjevXvdy44dO2ZZs2a1Bx980L0sfp8JDw+3uLg49/K+ffta+vTp7dy5c4leX7xhw4Yl6EmSZciQwfbs2eNetnXrVpNkb7/99i3rXe+zzz7zuG/++usvCwkJsa5du3psd+LECQsODvZYHh0dbUWLFrXSpUvbpUuXLCIiwoKCguzgwYMelw0MDPTYR25l+fLlJsm+/vrrRNf36NHDChQo4L4fly5dapJsy5YtHtsFBwdb9+7db3o9V69etcKFC1uhQoXszz//9Fh3/WPUoEEDK1u2rF26dMljfY0aNaxYsWLuZbf7GJ86dcoyZMhgERERHtu9+OKLJsnjfkpsv61Tp45JstmzZ7uXxcTEWGhoqLVo0cK97I033jBJtmDBAveyixcvWokSJRJ9Llzv3LlzJsmaNWt2023MzB599FGTZFFRUWb2v/20TZs2Htsl5TaPGjXKAgMD7ffff/eoMWjQIEufPr0dOnTIzG79WhFv7ty5JsnWr19/y9sBMC0B+Btmpi+++EKPPPKIzEx//PGH+9S4cWNFRkYm+NdoUnz22WcqWbKkSpQo4VG7fv36kpRgZKZOnToqVapUsm5TvPjR47/++uum24SEhGjHjh3avXu319fTokWLBP8KvZUePXq4/44fLb98+bKWL1/udQ9/JzY2VkuXLlXz5s095hzmyZNHbdu21Zo1axQVFeVxmW7dunn8q7127dqKjY31+nBX4eHhHqOg999/v4KCgrRv3z6v6knXRjPPnTunNm3aeOxf6dOnV7Vq1Tz2r8yZM2vmzJnatWuXHnzwQS1cuFBvvfWWChYs6PX1nzlzRpKULVu2BOuuXr2qTz75RE8++aT7fqxfv75y5cqlOXPmeGwbEhKi9evX69ixY4lez5YtW7R//3716dNHISEhHuvia589e1YrV65Uq1at9Ndff7nvizNnzqhx48bavXu3jh496nHZv3uMly9frsuXL6tnz54e2/Xp0+c27p1rsmTJ4jEvPkOGDKpatarH47548WLly5dPjz76qHtZxowZ1bVr17+tH//8zpo16y23i19/434eP2ofLym3+bPPPlPt2rWVLVs2j/0vPDxcsbGx+u677zy2v9VrRfw+9Mcff9zydgBMSwD+xunTp3Xu3Dm9++67evfddxPd5tSpU17X3717t3bt2nXTF/QbaxcuXNjr67pR/FEJbvWmN3LkSDVr1kzFixdXmTJl9NBDD6l9+/ZJ+uZ9UnpOly5dgi+0FC9eXJLu6JEmTp8+rQsXLui+++5LsK5kyZKKi4vT4cOHVbp0affyG0Nf/Jvvn3/+6VUPiYXIbNmyeV1PkvtDSfyHpRvd+O/dmjVr6l//+pcmT56sxo0b6+mnn/b6uq9niRytYunSpTp9+rSqVq2qPXv2uJfXq1dPH330kcaNG+c+qsCrr76qjh07qkCBAqpUqZKaNGmiDh06uPeVvXv3SpLKlClz0x727NkjM9OQIUM0ZMiQRLc5deqU8uXL5z7/d49xfMgtVqyYx3Y5c+ZMNNAnJn/+/AnmI2fLlk3btm1znz948KCKFCmSYLuiRYv+bf345/etPsRev/7G14Mbn79Juc27d+/Wtm3bfPL6Fr8P/dOOEY2kI9wCfyN+buhTTz2ljh07JrpNcg6xFBcXp7Jly+rNN99MdH2BAgU8zmfKlMnr67pR/EHRb/UG+eCDD2rv3r368ssvtXTpUv3nP//RW2+9palTp+qZZ565revxZc/Szd/cYmNjfXo9fyf+EGY3SizIpUQ96X/77wcffKDQ0NAE6288akNMTIz7y0l79+7VhQsXlDlzZq+vP36ucGIBPX50tlWrVoledvXq1apXr557m9q1a2v+/PlaunSpXnvtNY0bN07z5s1zz0v9O/H3Rf/+/dW4ceNEt7nxuXAnHpMb3enrCA4OVp48eTzCcmK2bdumfPnyJfjAk5znb1xcnBo2bKgXXngh0fXxH1xv57ri96F77rnH637wz0C4Bf5Gzpw5lTVrVsXGxio8PPyW295qROFm64oUKaKtW7eqQYMGd3VEIjY2VnPnzlXmzJnd34C+mezZs6tz587q3Lmzzp8/rwcffFDDhw93h1tf9h0XF6d9+/Z5vOn9/vvvkuT+8lz86NC5c+c8LpvYdIDb7S1nzpzKnDmzfvvttwTrfv31V6VLly7BB420IH6aQ65cuf52/5WkYcOGadeuXXr99dc1cOBADRo0SBMnTvTYJimPd4kSJSRJ+/fv91geHR2tL7/8Uk8++aRatmyZ4HK9evXSnDlz3OFWujZF5Pnnn9fzzz+vU6dOqWLFinrllVf08MMPu2/n9u3bb3o740d5/f39b+u+uB3xP0qxe/duj/84nD59Olkj7oldz86dO2VmHvf/9SPet9K0aVO99957WrNmTaLP9++//14HDhzQs88+e1u9SLd3m4sUKaLz58/75P7ev3+/0qVLlyAQAzdizi3wN9KnT68WLVroiy++SPTnH68/LFD88R9vDF3x664/5Fa8Vq1a6ejRo3rvvfcSrLt48aKio6OT0X3iYmNj1atXL+3atUu9evW65TeP4+dMxsuSJYuKFi3qcZiyW91ub0yaNMn9t5lp0qRJ8vf3V4MGDSRde3NNnz59gvl677zzToJat9tb+vTp1ahRI3355Zce0x9OnjypuXPnqlatWmnyG9qNGzdWUFCQRo8erStXriRYf/3+u379er3++uvq06eP/v3vf2vAgAGaNGmSVq9e7XGZwMDA236s8+XLpwIFCiT4BcD58+crOjpa3bt3V8uWLROcmjZtqi+++EIxMTGKjY1N8NzJlSuX8ubN694PK1asqMKFC2v8+PEJeosfAc2VK5fq1q2radOm6fjx47e8L25XeHi4/P399fbbb3uMtPr61wgbN26so0ePehyy7NKlS4m+biRmwIABypQpk5599tkEz+mzZ8/queeeU+bMmTVgwIC/rZWU29yqVSutXbtWS5YsSbDu3Llzunr16m31L0mbNm1S6dKlFRwcfNuXwT8TI7fA/zd9+vREjynau3dvjR07VqtWrVK1atXUtWtXlSpVSmfPntXmzZu1fPlynT17VtK1UYqQkBBNnTpVWbNmVWBgoKpVq6bChQurUqVK+uSTT9SvXz9VqVJFWbJk0SOPPKL27dvr008/1XPPPadVq1apZs2aio2N1a+//qpPP/1US5YsSdYvp0VGRurDDz+UdO2wPPG/ULZ37161bt1ao0aNuuXlS5Uqpbp166pSpUrKnj27Nm7c6D4kU7xKlSpJujba1rhxY6VPn16tW7f2qt+MGTNq8eLF6tixo6pVq6ZFixZp4cKFevHFF93z9oKDg/XEE0/o7bfflsvlUpEiRfTNN98kOvc5Kb29/PLLWrZsmWrVqqXnn39efn5+mjZtmmJiYhI97mhaEBQUpClTpqh9+/aqWLGiWrdurZw5c+rQoUNauHChatasqUmTJunSpUvq2LGjihUrpldeeUWSNGLECH399dfq3LmzfvnlF/cHhUqVKmn58uV68803lTdvXhUuXDjBYdKu16xZM82fP99j1HHOnDnKkSOHatSokehlHn30Ub333ntauHCh6tevr/z586tly5YqV66csmTJouXLl2vDhg164403JF2bqz1lyhQ98sgjKl++vDp37qw8efLo119/1Y4dO9zhavLkyapVq5bKli2rrl276t5779XJkye1du1aHTlyRFu3bk3S/ZszZ071799fY8aMUdOmTdWkSRNt2bJFixYt8um/z5999llNmjRJbdq0Ue/evZUnTx7NmTPH/aMQfzeaXqxYMc2aNUvt2rVT2bJlE/xC2R9//KGPPvrotn79Kym3ecCAAfrqq6/UtGlTderUSZUqVVJ0dLR++eUXff755zpw4MBt3U9XrlzR6tWr9fzzz//ttgCHAsM/Xvwhf252Onz4sJmZnTx50rp3724FChQwf39/Cw0NtQYNGti7777rUe/LL7+0UqVKmZ+fn8dhqc6fP29t27a1kJAQk+RxWLDLly/buHHjrHTp0hYQEGDZsmWzSpUq2YgRIywyMtK9naRbHg7pRvGHGYo/ZcmSxYoVK2ZPPfWULV26NNHL3HgosJdfftmqVq1qISEhlilTJitRooS98sordvnyZfc2V69etZ49e1rOnDnN5XK5D3MVf3if1157LcH13OxQYIGBgbZ3715r1KiRZc6c2XLnzm3Dhg2z2NhYj8ufPn3aWrRoYZkzZ7Zs2bLZs88+a9u3b09Q82a9xd+f1x8KzMxs8+bN1rhxY8uSJYtlzpzZ6tWrZz/++KPHNjc7fNzNDlF2o5sdCiyxx/bGx+Pv3HgosOt7a9y4sQUHB1vGjBmtSJEi1qlTJ9u4caOZ/e8QVzceZmnjxo3m5+dn//rXv9zLfv31V3vwwQctU6ZMCQ79lJjNmzebJPfh7k6ePGl+fn7Wvn37m17mwoULljlzZnvssccsJibGBgwYYOXKlbOsWbNaYGCglStXzt55550El1uzZo01bNjQvd3999+f4FBqe/futQ4dOlhoaKj5+/tbvnz5rGnTpvb555+7t0nKYxwbG2sjRoywPHnyWKZMmaxu3bq2ffv2BI/dzQ4Fltjh+jp27Jjg0IH79u2ziIgIy5Qpk+XMmdP+/e9/2xdffGGSbN26dTe9L6+3bds2a9OmjeXJk8f9OtamTRv75ZdfEmwbv5/GH4Lverd7m82uHY5u8ODBVrRoUcuQIYPdc889VqNGDXv99dfdryO3eq0wM1u0aJFJst27d9/W7cQ/m8vMh7PiAQBIRIMGDZQ3b97b+jEN3L7x48erb9++OnLkiMdRHpymefPmcrlcmj9/fkq3gjSAcAsAuOPWr1+v2rVra/fu3e4vJCFpLl686HE0gUuXLqlChQqKjY11f+nSiXbt2qWyZcvq559/vuWh3oB4hFsAANKAhx9+WAULFlT58uXdc+l37NihOXPmqG3btindHpBq8IUyAADSgMaNG+s///mP5syZo9jYWJUqVUoff/yxnnzyyZRuDUhVGLkFAACAY3CcWwAAADgG4RYAAACOwZxbXfu5z2PHjilr1qx39edPAQAAcHvMTH/99Zfy5s2rdOluPj5LuJV07NixNPmb8QAAAP80hw8fVv78+W+6nnArKWvWrJKu3Vlp8bfjAQAAnC4qKkoFChRw57abIdzqf7/JHRQURLgFAABIxf5uCilfKAMAAIBjEG4BAADgGCkabr/77js98sgjyps3r1wulxYsWHDTbZ977jm5XC6NHz/eY/nZs2fVrl07BQUFKSQkRF26dNH58+fvbOMAAABIlVI03EZHR6tcuXKaPHnyLbebP3++1q1bp7x58yZY165dO+3YsUPLli3TN998o++++07dunW7Uy0DAAAgFUvRL5Q9/PDDevjhh2+5zdGjR9WzZ08tWbJEERERHut27dqlxYsXa8OGDapcubIk6e2331aTJk30+uuvJxqGAQAA4Fypes5tXFyc2rdvrwEDBqh06dIJ1q9du1YhISHuYCtJ4eHhSpcundavX3/TujExMYqKivI4AQAAIO1L1eF23Lhx8vPzU69evRJdf+LECeXKlctjmZ+fn7Jnz64TJ07ctO6YMWMUHBzsPvEDDgAAAM6QasPtpk2bNGHCBM2cOdPnP4k7ePBgRUZGuk+HDx/2aX0AAACkjFQbbr///nudOnVKBQsWlJ+fn/z8/HTw4EH9+9//VlhYmCQpNDRUp06d8rjc1atXdfbsWYWGht60dkBAgPsHG/jhBgAAAOdItb9Q1r59e4WHh3ssa9y4sdq3b6/OnTtLkqpXr65z585p06ZNqlSpkiRp5cqViouLU7Vq1e56zwAAAEhZKRpuz58/rz17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4BiEWwAAADgG4RYAAACOQbgFAACAYxBuAQAA4BiEWwAAADiGV+F23759vu4DAAAASDavwm3RokVVr149ffjhh7p06ZKve3KLjY3VkCFDVLhwYWXKlElFihTRqFGjZGbubcxMQ4cOVZ48eZQpUyaFh4dr9+7dd6wnAAAApF5e/YjD5s2bNWPGDPXr1089evTQk08+qS5duqhq1ao+bW7cuHGaMmWKZs2apdKlS2vjxo3q3LmzgoOD1atXL0nSq6++qokTJ2rWrFkqXLiwhgwZosaNG2vnzp3KmDGjT/sBAOBu8MUP/Uj82A/+mbwauS1fvrwmTJigY8eOafr06Tp+/Lhq1aqlMmXK6M0339Tp06d90tyPP/6oZs2aKSIiQmFhYWrZsqUaNWqkn376SdK1Udvx48fr//7v/9SsWTPdf//9mj17to4dO6YFCxb4pAcAAACkHcn6Qpmfn58ef/xxffbZZxo3bpz27Nmj/v37q0CBAurQoYOOHz+erOZq1KihFStW6Pfff5ckbd26VWvWrNHDDz8sSdq/f79OnDih8PBw92WCg4NVrVo1rV279qZ1Y2JiFBUV5XECAABA2pescLtx40Y9//zzypMnj9588031799fe/fu1bJly3Ts2DE1a9YsWc0NGjRIrVu3VokSJeTv768KFSqoT58+ateunSTpxIkTkqTcuXN7XC537tzudYkZM2aMgoOD3acCBQokq08AAACkDl7NuX3zzTc1Y8YM/fbbb2rSpIlmz56tJk2aKF26a1m5cOHCmjlzpsLCwpLV3Keffqo5c+Zo7ty5Kl26tH7++Wf16dNHefPmVceOHb2uO3jwYPXr1899PioqioALAADgAF6F2ylTpujpp59Wp06dlCdPnkS3yZUrl95///1kNTdgwAD36K0klS1bVgcPHtSYMWPUsWNHhYaGSpJOnjzp0cfJkydVvnz5m9YNCAhQQEBAsnoDAABA6uNVuL2dQ21lyJAhWaOrknThwgX3aHC89OnTKy4uTtK1EeLQ0FCtWLHCHWajoqK0fv16/etf/0rWdQMAACDt8SrczpgxQ1myZNETTzzhsfyzzz7ThQsXkh1q4z3yyCN65ZVXVLBgQZUuXVpbtmzRm2++qaefflqS5HK51KdPH7388ssqVqyY+1BgefPmVfPmzX3SAwAAANIOr75QNmbMGN1zzz0JlufKlUujR49OdlPx3n77bbVs2VLPP/+8SpYsqf79++vZZ5/VqFGj3Nu88MIL6tmzp7p166YqVaro/PnzWrx4Mce4BQAA+AfyauT20KFDKly4cILlhQoV0qFDh5LdVLysWbNq/PjxGj9+/E23cblcGjlypEaOHOmz6wUAAEDa5NXIba5cubRt27YEy7du3aocOXIkuykAAADAG16F2zZt2qhXr15atWqVYmNjFRsbq5UrV6p3797uIxsAAAAAd5tX0xJGjRqlAwcOqEGDBvLzu1YiLi5OHTp08OmcWwAAACApvAq3GTJk0CeffKJRo0Zp69atypQpk8qWLatChQr5uj8AAADgtnkVbuMVL15cxYsX91UvAAAAQLJ4FW5jY2M1c+ZMrVixQqdOnXL/qEK8lStX+qQ5AAAAICm8Cre9e/fWzJkzFRERoTJlysjlcvm6LwDJFDZoYbJrHBgb4YNOAAC4e7wKtx9//LE+/fRTNWnSxNf9AAAAAF7z6lBgGTJkUNGiRX3dCwAAAJAsXoXbf//735owYYLMzNf9AAAAAF7zalrCmjVrtGrVKi1atEilS5eWv7+/x/p58+b5pDkAAAAgKbwKtyEhIXrsscd83QsAAACQLF6F2xkzZvi6DwAAACDZvJpzK0lXr17V8uXLNW3aNP3111+SpGPHjun8+fM+aw4AAABICq9Gbg8ePKiHHnpIhw4dUkxMjBo2bKisWbNq3LhxiomJ0dSpU33dJwAAAPC3vBq57d27typXrqw///xTmTJlci9/7LHHtGLFCp81BwAAACSFVyO333//vX788UdlyJDBY3lYWJiOHj3qk8YAAACApPJq5DYuLk6xsbEJlh85ckRZs2ZNdlMAAACAN7wKt40aNdL48ePd510ul86fP69hw4bxk7wAAABIMV5NS3jjjTfUuHFjlSpVSpcuXVLbtm21e/du3XPPPfroo4983SMAAABwW7wKt/nz59fWrVv18ccfa9u2bTp//ry6dOmidu3aeXzBDAAAALibvAq3kuTn56ennnrKl70AAAAAyeJVuJ09e/Yt13fo0MGrZgAAAIDk8Crc9u7d2+P8lStXdOHCBWXIkEGZM2cm3AIAACBFeHW0hD///NPjdP78ef3222+qVasWXygDAABAivEq3CamWLFiGjt2bIJRXQAAAOBu8Vm4la59yezYsWO+LAkAAADcNq/m3H711Vce581Mx48f16RJk1SzZk2fNAYAAAAklVfhtnnz5h7nXS6XcubMqfr16+uNN97wRV8AAABAknkVbuPi4nzdBwAAAJBsPp1zCwAAAKQkr0Zu+/Xrd9vbvvnmm95cBQAAAJBkXoXbLVu2aMuWLbpy5Yruu+8+SdLvv/+u9OnTq2LFiu7tXC6Xb7oEACAVChu00Cd1DoyN8EkdAF6G20ceeURZs2bVrFmzlC1bNknXftihc+fOql27tv7973/7tEkAAADgdng15/aNN97QmDFj3MFWkrJly6aXX36ZoyUAAAAgxXgVbqOionT69OkEy0+fPq2//vor2U0BAAAA3vAq3D722GPq3Lmz5s2bpyNHjujIkSP64osv1KVLFz3++OO+7hEAAAC4LV7NuZ06dar69++vtm3b6sqVK9cK+fmpS5cueu2113zaIAAAAHC7vAq3mTNn1jvvvKPXXntNe/fulSQVKVJEgYGBPm0OAAAASIpk/YjD8ePHdfz4cRUrVkyBgYEyM1/1BQAAACSZV+H2zJkzatCggYoXL64mTZro+PHjkqQuXbpwGDAAAACkGK/Cbd++feXv769Dhw4pc+bM7uVPPvmkFi9e7LPmAAAAgKTwas7t0qVLtWTJEuXPn99jebFixXTw4EGfNAYA8A1f/IoWv6AFIK3wauQ2OjraY8Q23tmzZxUQEJDspgAAAABveBVua9eurdmzZ7vPu1wuxcXF6dVXX1W9evV81hwAAACQFF5NS3j11VfVoEEDbdy4UZcvX9YLL7ygHTt26OzZs/rhhx983SMAAABwW7wauS1Tpox+//131apVS82aNVN0dLQef/xxbdmyRUWKFPF1jwAAAMBtSfLI7ZUrV/TQQw9p6tSpeumll+5ETwAAAIBXkjxy6+/vr23btt2JXgAAAIBk8WpawlNPPaX333/f170AAAAAyeLVF8quXr2q6dOna/ny5apUqZICAwM91r/55ps+aQ4AAABIiiSF23379iksLEzbt29XxYoVJUm///67xzYul8t33QEAAABJkKRwW6xYMR0/flyrVq2SdO3ndidOnKjcuXPfkeYAAACApEjSnFsz8zi/aNEiRUdH+7QhAAAAwFtefaEs3o1h9044evSonnrqKeXIkUOZMmVS2bJltXHjRo8ehg4dqjx58ihTpkwKDw/X7t2773hfAAAA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Je/DX2RkpOrWratVq1b5qj1JUkxMjD7//HOtXr3ap3U//vhjPfTQQ9q5c6cOHTrk09p3jSHVmD9/voWFhVnJkiUtU6ZM9vTTT9uxY8eSXGfhwoX2888/u89/8cUXVq1aNStSpIg1b97c3n///WT3+ttvv1nhwoXtnXfeSXateHFxcWZm9sknn1irVq2sevXqljlzZitatKgtXLgw2fU///xzCw4OttatW1uNGjWscuXK1q1bN69qXbhwwerXr2/PPPOMlSpVytq1a+ded/Xq1WT32r9/f2vRooXVqFHDsmfPbvfdd59X98GN+8K8efOsZs2aVrx4cRs+fLht3rw52b1GRkZauXLlrF27drZjx45k17vRzJkz7cEHH7SOHTvaxYsXvaqxcOFC27p1q5n9bz974okn7I033vBZn5s3b7aKFSvaM888Y9u3b/dZ3Xjz58+3LFmyWNGiRS0gIMCmTZtmUVFRya7p6/3hs88+sxw5clj58uUtXbp0Vr16dfvss8+SXXfgwIFWokQJu+eee6xOnTo+e+3p37+/PfbYY1alShULCQnx+rl2vd27d9vQoUNt8ODBZva/fS65vvnmG8uUKZO99957Xr033OjPP/+0atWqmcvlsn/961/u5bGxscmuHW/69OmWL18+69Wrl+3cudNndc3Mdu3aZYGBgTZz5kyf1bxw4YL77wcffNDq1KmT7JqXLl2yypUr24wZM5JdK178PrVx40YLCgqyL7/80id1P/vsM3O5XDZ//nxr27atDRs2zMx88752NxFuU4klS5ZYSEiITZs2zWJiYmzRokXmcrmsdevWdvjw4duuc+LECStcuLB17tzZ9u7dazt27LCsWbPayy+/bGPHjrXnn3/eMmTIYKNHj05Wv8uWLbPixYvbgQMH3Mt88QK+bt06y5w5s73//vv266+/2u7du61u3bpWvXp1++9//+t13Z07d1rBggVt6tSp7vOZMmVyv/l4Izo62szM3n//fbvvvvt8FnBnzJhhISEhtmnTJjt79qwdP37cGjVqZNWrV7dFixbddp3r94U9e/bYrl27LCQkxEaNGmW9e/e2ihUrWosWLez777/3utd4GzZssKpVq/o02F2/P82YMcPrgHv9/XB9+K5du7a9+eabPuk13p0IuHFxcXbmzBmrWbOmTZs2zXbv3m2jR482l8tlo0ePtnPnznlVd9OmTRYcHGwjR4702f6wefNmu+eee+w///mPnT171k6cOGEdO3a0Bx980ObNm+d13Y8++shCQ0NtwYIFNnPmTBswYID5+/vbmDFjvK5pZjZr1izLli2bbdq0yf744w87evSoNWzY0B544IEkPdeuFxkZaZUrV7acOXNa37593cuT+/p48eJFe+KJJ+zFF180s2uvP3v37rVXXnnF5s+f79UHncuXL1v9+vWtfPny1rBhQ/vwww/d63wZcGfNmmX33Xefde/e3WcBN76/Pn36WIsWLezMmTPJrrl48WJ76qmnbMmSJWZmdvDgQStatKiNHDnSq3rXv1Z16tTJ/R4RFxfns/s3MjLSWrVqZb179zaz5D1u8+bNM5fLZdOnTzczs6ZNm7o/9PjqA9rdQrhNBSIjI61bt242YsQIMzPbt2+fFSlSxFq2bGkhISHWrFkzO3jw4G3X27Rpk1WuXNm6d+9uL730kvXv39/juiZNmmQZM2a02bNne93z/PnzrUCBAu5we/0T6ttvv7VNmzZ5VXfatGlWqlQpj0/PR44csVq1alnRokXdLzpJtWTJEqtQoYKZXbt/CxUq5DFq622/ZmZ//fWXTZ8+3UqUKOGTgPvSSy9ZrVq1LDY21n2/HjlyxKpVq2ZFixZN0ptu/L7Qo0cPGzVqlI0aNcq97ptvvrF69epZ8+bNfRJw71Swi5ecgLtp0yarUqWKPfPMM/bLL7+YmVmjRo3cb+aXL182M/O4z73l6/vh4sWLduHCBXvxxRft7Nmz7uUTJkxwB9zIyMgk1dyzZ4+NGjXKXn75ZfcyX+wPc+bMsVKlSllkZKT7sTtx4oS1a9fOateubTExMUmuuWrVKnvmmWc8PohERUXZ22+/bYGBgckaFR46dKjVrFnTYmNj3f0eOXLEqlatmuTn2vU2b95sxYoVs/Lly7v/Y5BcFy5csMqVK1vPnj3tzJkz1qNHD6tTp47lz5/fcufO7fHcTopLly7Z8ePHLSIiwurVq+cRcM28ex3bu3evHT161GPZjBkzrESJEvavf/3Lfv/9d696/fbbb+2DDz7weI5+8cUXliNHDvc+6+3zNy4uzrp27Woul8uyZ89uw4YNs3379tkrr7xirVq1SvJ7xKJFi6xOnToWERFhY8eOtbp161rbtm3t4sWL7tcbb7z55pv2+uuvewx6vfvuuxYYGGh79uxx3xZv/Pe//7U5c+a4z/fs2dPat2/vsc3u3bu9qn23EW5TgZiYGPv0009tz549dubMGatQoYJ16dLFzK6NWLhcLmvSpIkdOXLktmtu2rTJqlataoUKFbLu3bt7rDt37px17tzZ2rZta5cvX/bqibBv3z7LlCmTexThen369LGhQ4d69QSePXu23XfffXbq1Ckz+1/o2LZtm2XJksXuv/9+r95wli5dak2aNLH9+/db/vz5rVu3bu4X7R9++MEGDhxohw4dSnLdeOfPn7fp06dbmTJl7NFHH/WqRvzjMHLkSKtcubI7wMXfBytXrrTMmTNbgwYNbMWKFbdd9/p9YeDAgR7rvv76a6tbt661bNnSVq5c6VXf17s+2PlqisL1++f06dPtwQcftE6dOtmlS5e86u3pp5+2X375xZ588slE78fz588nu2df3Q8LFiywxo0bW6lSpaxEiRIJgtKECRPM39/fhgwZctsBN35kMVeuXDZo0CCPdcndHz766CMrUqSIHT9+3MzMrly5YmZm+/fvN5fLZcuWLUtSvePHj1uRIkXc/3263tmzZ6158+bWq1cvM0vaG3r8tmPGjLHKlSu7P0zHP9eWL19umTJlsnr16tlXX32VpJ7jbd261e6//36fftibNWuWZcqUyYKCguyxxx6zWbNmmdm119x69eol64PZ3r17LSIiwho0aGAffPCBmV37oN21a9ck3bdnz561PHny2Isvvphg6sR//vMf8/f3t549e9q2bduS1F9MTIz16dPHXC6XPf744/baa6+513Xt2tVq1Khhf/31V5Jq3mj9+vXWpk0be+WVV6xy5cr23HPP2TPPPGMlS5a0t956y8xufz9bvXq1jRs3zlq3bm0tW7a0/Pnzm8vlskaNGlmZMmWse/fuNnDgwCR9kLxw4YINHDjQgoODrX79+vb000/bmTNn7OLFi9auXTt7/vnnkxWc48XfxldeecWqVavmfq8cNmyYVapUKckfplMC4TaViA8yH3zwgVWvXt39qeyjjz6yunXrWqFChZI0emt27cU1LCzMSpQoYVu2bPFY9+KLL1r58uWT9UR4//33zd/f3wYMGGC//PKL7dy501544QULCQmxXbt2eVVz9+7dljFjRhsyZIjH8o0bN1qdOnWsTZs2Sb4fzK69uWbOnNlcLpf7zTBer169rFGjRh6jYt44f/68vfPOO1a1atUEoxZJsW3bNkufPr0NHz7cY/nixYutRYsWVr9+fQsPD0/SY7d161YrXLiw1axZM8Eb7cKFC61ChQrWrl07jxFzb23evNmqVq1qrVu39no/uNH1byjxc3CHDh2a5DfzzZs3W+XKla1jx46WJUsWu/feey08PNwaNmxo9evXtzp16linTp1Sxf2wYcMGCwoKsueee846depk/v7+1rt3b4+pQGZmY8eOtWzZstkff/yRpN6KFy/u8/1hz549FhAQYP/3f//nsfzAgQNWtmxZW7duXZLqmV3bd4sUKWIVK1ZMMCe4S5cu9vDDDye5Zrzt27ebn59fgufawoULrXnz5vb4449b7dq1vZ6Deyc+7O3YscOWLl1qZv8bpezevbt16NAhyR/4brRv3z577LHHrEyZMlalShULCgry6jFbtWqVhYWF2YgRIxK8FlaqVMmCg4PthRde8Gokf+fOnfavf/3LSpQoYSVKlLDp06fbhAkT7NFHH/XqPw4rVqyw9957z8yu3Z89evSwp59+2qKiouydd96xZ555xlwul7lcLq/ui3jLly+3kJAQe/3112348OHWqVMnK126tHu0NSkOHz5s7777rlWsWNFKlChhHTp0sIiICIuIiHAH/ORMI4i/7KRJk+y+++4zM7Phw4ebv7+/bdy40eu6dxPhNpUZOXKklSlTxh20Bg0aZG+//bbXIXTbtm1WtmxZ69Spk8cXi7p162bh4eHJGqWKjY21Tz/91LJly2b58+e3okWL2n333ZfsL6V88MEH5u/vby+++KLt37/f/vzzTxsyZIh17NgxWZ8YFyxYYIGBgTZw4ED7/fff7ZdffrH+/ftbSEiI+1/VyRUdHe31HMjrzZgxw/3BYePGje5RlVdeecV27tzp1SjY1q1brXz58tatW7cEgWbJkiUJQlNy/PTTT1anTh2ffOkl3vUv1v3797datWp59ea4adMmK1u2rJUrV87atm1rs2bNsgkTJtiwYcNszJgxPv0ymLf3w549e2zo0KEec0rfeecdy58/vw0aNCjBY+XNB7M7tT98+OGHliFDBhs0aJDt3r3bTp48aS+99JIVKFDA6w99W7dutXLlylmHDh3cH9SjoqKsRo0a1rVrV69qxot/rvXv399++ukn27Nnj0VERNiQIUPs2LFj1qpVKytbtqzXU6Lu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", - "text/plain": [ - "<Figure size 800x600 with 1 Axes>" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Put your code here\n" ] @@ -316,121 +257,29 @@ "<img src=\"340px-English-slf.png\" alt=\"Letter Frequencies English\" width=\"500\" height=\"auto\">\n", "This should look roughly similar, as we are using an English text.\n", "\n", - "Now we use our cypher using a random key. Can you figure out the correct key from the frequency analysis of the cypher text and the standard English letter distribution? Try out your guess by decoding the cypher text!" + "Now we use our encryption with a random key. Can you figure out the correct key from the frequency analysis of the cypher text and the standard English letter distribution? Try out your guess by decoding the cypher text!" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "8ae904cd", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAArcAAAIpCAYAAAC48RBEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8WgzjOAAAACXBIWXMAAA9hAAAPYQGoP6dpAABZ+ElEQVR4nO3deXhMd///8deQBSEJitijllprp7baghYtLVVLbVXau3Y3RXvbW0tXlKK9a2vpji5uO9VqUVuppa1930olFQTJ+/eHX+ZrJFQmQ5LT5+O65roy55x5z3tmzsy85pPPnHGZmQkAAABwgHQp3QAAAADgK4RbAAAAOAbhFgAAAI5BuAUAAIBjEG4BAADgGIRbAAAAOAbhFgAAAI5BuAUAAIBjEG4BAADgGIRbAB7Cw8PVqVOnO349Bw4ckMvl0syZM93LOnXqpMyZM9/x647ncrk0fPjwu3Z98YYPHy6Xy3XXrzcl/fTTTwoICNDBgwdTupW75sbn0rfffiuXy6Vvv/02xXq60+7E68fOnTvl5+en7du3+7QunItwi3+8mTNnyuVyaePGjcmudezYMQ0fPlw///xzgnVz587V+PHjk30dSVGnTh25XC65XC6lS5dOwcHBuu+++9S+fXstW7bMZ9fzv//9L0VC4u1Izb35wvWP8a1OvrwPRo8erQULFiTpMi+99JLatGmjggULJrq+SpUqcrlcmjJlig86xM3s2LFDTz31lPLmzavAwEDlyZNH7dq1044dO1K6tZsqWbKkmjRpoqFDh6Z0K0gjXGZmKd0EkJJmzpypzp07a8OGDapUqVKyam3cuFGVK1fWjBkzEoxeNG3aVNu3b9eBAweSdR1JUadOHe3du1djxoyRJEVHR2vPnj2aN2+e9u3bp1atWunDDz+Uv7+/+zIxMTFKly6dx7K/06NHD02ePFlJeTkxM8XExMjf31/p06eXdG3k9vPPP9f58+dvu05yert06ZL8/Pzk5+fns+u7HVevXtXVq1eVIUOGZNdatmyZTp486T6/YcMGTZw4US+++KJKlCjhXn7//ffr/vvvT/b1SVLmzJnVsmVLj1H3W/n5559Vvnx5/fjjj6pWrVqC9bt371axYsUUHh6uvHnzas2aNT7pM6WFh4erTp067vspLi5Oly9fVkBAgNKlu/tjS/PmzVObNm2ULVs2denSRYUKFdKBAwf0/vvv68yZM/r444/12GOPJes6brzNvrJo0SI1btxYe/bsUeHChX1aG85zd1/RAfhU/JvlrUJSSEiInnrqKY9lY8eOVa9evfTOO+8oPDxc48aNc68LDAy8Y/1K14JdXFycAgICfBLukiOlrt+XgbpBgwYe5zNkyKCJEyeqQYMGqlOnjk+uI7lmzJihAgUK6IEHHkh0/YcffqicOXPqjTfeUMuWLXXgwAGFh4ff3SbvgnTp0qXYPrd37161b99e9957r7777jvlyJHDva53796qVauW2rdvr23btunee++9aZ3o6GgFBQXdjZY9XisiIiKUNWtWzZo1SyNHjrwr14+0i2kJwG06evSonn76aeXKlUuBgYEqVaqUpk+f7l7/7bffqnLlypKkzp07u/8dPHPmTNWpU0cLFy7UwYMH3cuvf/OOiYnRsGHDVKRIEQUGBip//vx64YUXFBMT49GDy+VSjx49NGfOHJUqVUqBgYFavHhxkm9L+vTpNXHiRJUsWVKTJk1SZGSke92Nc+auXLmiESNGqGjRosqQIYOyZ8+umjVruqc1dOrUSZMnT3b3F3+S/m9e7euvv67x48ercOHCCgwM1M6dOxOdcxtv3759atSokYKCgpQnTx6NHDnSY+T1ZnMXb6x5q97il9347/otW7bo4YcfVnBwsDJnzqz69etr3bp1HtvET2X54Ycf1K9fP+XIkUNBQUF67LHHdPr06b+9/xObcxv/2C5YsEClS5d272PePL6JWbRokWrVqqWgoCBlyZJFTZo08fhX9MqVK5UuXboE//qdO3eux3QBl8ul6OhozZo1y31//t0cywULFqhevXo3nWc8d+5ctWzZUk2bNlVISIjmzp2bYJu//vpLffr0UXh4uAIDA5UzZ041aNBAmzdv9thu/fr1aty4sbJmzaqgoCDdf//9mjBhgsc2v/76q1q2bKls2bIpQ4YMqlSpkr766iuPbZLyGJuZXn75ZeXLl0+ZMmVS3bp1E/03f2L7bZ06dVS6dGnt3LlTdevWVaZMmZQ3b169+uqrCS5/8OBBPfroowoKClLOnDnVt29fLVmy5Lbm8b722mu6cOGC3n33XY9gK0n33HOPpk2bpujoaI/rjd9Pd+7cqbZt2ypr1qyqWbNmkm6zJJ07d059+vRR/vz5FRgYqCJFimjcuHGKi4tzb3Or1wpJ8vf3V506dfTll1/e8nYCEiO3wG05efKkHnjgAXcAyZEjhxYtWqQuXbooKipKffr0UYkSJTRy5EgNHTpU3bp1U61atSRJ1atXV968eRUZGakjR47orbfekiT3F6fi4uL06KOPas2aNerWrZtKlCihX375RW+99ZZ+//33BHMbV65cqU8//VQ9evTQPffc4/UIV/r06dWmTRsNGTJEa9asUZMmTRLdbvjw4RozZoyeeeYZValSRVFRUdq4caM2b96sBg0a6Nlnn9WxY8e0bNkyffDBB4nWmDFjhi5duqRu3bopMDBQ2bJl83hju15sbKweeughPfDAA3r11Ve1ePFiDRs2TFevXk3yiM3t9Ha9HTt2qFatWgoODtYLL7wgf39/TZs2TXXq1NHq1atVtWpVj+179uyprFmzatiwYTpw4IDGjx+vHj166JNPPklSn/HWrFmjefPm6fnnn1eWLFk0ceJEtWjRQocOHVL27Nm9qilJH3zwgTp27KhGjRpp3LhxunDhgqZMmaKaNWtqy5YtCg8PV7169fT8889rzJgxat68uSpUqKDjx4+rZ8+eioiI0HPPPeeuFb8vdOvWTZJu+W/io0eP6tChQ6pQoUKi69evX689e/ZoxowZCggI0OOPP645c+boxRdf9Njuueee0+eff64ePXqoZMmSOnPmjNasWaNdu3a5ay9btkxNmzZV7ty51bt3b4WFhWnXrl365ptv1Lt3b0nXHuMaNWoob968GjRokIKCgvTpp5+qefPm+uKLLxL8W/52HuOhQ4fq5ZdfVuPGjdW4cWNt3rxZDRs21OXLl2/r8fnzzz/10EMP6fHHH1erVq30+eefa+DAgSpTpowefvhhSddGTOvVq6fjx4+7b9vcuXO1atWq27qOr7/+WuHh4e7XpRs9+OCDCg8P18KFCxOse+KJJ1S0aFGNHj3a/SHzdm/zhQsXVLt2bR09elTPPvusChQooB9//FGDBw/W8ePHE3wPIbHXingVK1bUl19+qaioKAUHB9/W7cY/lAH/cDNmzDBJtmHDhptu06VLF8udO7f98ccfHstbt25tISEhduHCBTMz27Bhg0myGTNmJKjRpEkTK1iwYILlH3zwgaVLl86+//57j+VTp041SfbDDz+4l0mydOnS2Y4dO27rttWuXdtKlSp10/Xz5883STZhwgT3soIFC1rHjh3d58uW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1qZNG8udO7f7daxNmzb2yy+/JNg2fj+NPwTf9W73NptdOxzd4MGDrUiRIhYQEGD33HOPVa9e3V5//XX368itXivMzBYtWmSSbPfu3bd1O/HP5jLz4ax4AAASUb9+feXJk+e2fkwDt2/8+PHq27evjhw54nGUB6dp3ry5XC6X5s+fn9KtIA0g3AIA7rj169erVq1a2r17t/sLSUiaixcvehxN4NKlSypfvrxiY2PdX7p0ol27dqlMmTL6+eefb3moNyAe4RYAgDTg4YcfVoECBVSuXDn3XPodO3Zozpw5atu2bUq3B6QafKEMAIA0oFGjRvrvf/+rOXPmKDY2ViVLltTHH3+sJ598MqVbA1IVRm4BAADgGBznFgAAAI5BuAUAAIBjMOdW137u89ixY8qSJctd/flTAAAA3B4z019//aU8efIoXbqbj88SbiUdO3YsTf5mPAAAwD/N4cOHlS9fvpuuJ9xKypIli6Rrd1Za/O14AAAAp4uKilL+/Pndue1mCLf6v9/kDg4OJtwCAACkYn83hZQvlAEAAMAxCLcAAABwjBQNt999950eeeQR5cmTRy6XSwsWLLjpts8995xcLpfGjx/vsfzs2bNq166dgoODFRoaqi5duuj8+fN3tnEAAACkSikabqOjo1W2bFlNnjz5ltvNnz9f69atU548eRKsa9eunXbs2KFly5bpm2++0Xfffadu3brdqZYBAACQiqXoF8oefvhhPfzww7fc5ujRo+rZs6eWLFmiJk2aeKzbtWuXFi9erA0bNqhSpUqSpLfffluNGzfW66+/nmgYBgAAgHOl6jm3cXFxat++vQYMGKBSpUolWL927VqFhoa6g60kRUREKF26dFq/fv1N68bExCgqKsrjBAAAgLQvVYfbcePGyc/PT7169Up0/YkTJ5QzZ06PZX5+fsqWLZtOnDhx07pjxoxRSEiI+8QPOAAAADhDqg23mzZt0oQJEzRz5kyf/yTu4MGDFRkZ6T4dPnzYp/UBAACQMlJtuP3+++916tQpFShQQH5+fvLz89PBgwf173//W+Hh4ZKksLAwnTp1yuNyV69e1dmzZxUWFnbT2oGBge4fbOCHGwAAAJwj1f5CWfv27RUREeGxrFGjRmrfvr06d+4sSapWrZrOnTunTZs2qWLFipKklStXKi4uTlWrVr3rPQMAACBlpWi4PX/+vPbs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99q7d6+k5H34i4yMVJ06dbRq1SpftSdJiomJ0eeff67Vq1f7tO7HH3+shx56SDt37tShQ4d8WvuuMaQa8+fPt/DwcCtRooRlzJjRnn76aTt27FiS6yxcuNB+/vln9/kvvvjCqlataoULF7bmzZvb+++/n+xef/vtNytUqJC98847ya4VLy4uzszMPvnkE2vVqpVVq1bNMmXKZEWKFLGFCxcmu/7nn39uISEh1rp1a6tevbpVqlTJunXr5lWtCxcuWL169eyZZ56xkiVLWrt27dzrrl69muxe+/fvby1atLDq1atbtmzZ7L777vPqPrhxX5g3b57VqFHDihUrZsOHD7fNmzcnu9fIyEgrW7astWvXznbs2JHsejeaOXOmPfjgg9axY0e7ePGiVzUWLlxoW7duNbP/28+eeOIJe+ONN3zW5+bNm61ChQr2zDPP2Pbt231WN978+fMtc+bMVqRIEQsMDLRp06ZZVFRUsmv6en/47LPPLHv27FauXDlLly6dVatWzT777LNk1x04cKAVL17c7rnnHqtdu7bPXnv69+9vjz32mFWuXNlCQ0O9fq5db/fu3TZ06FAbPHiwmf3fPpdc33zzjWXMmNHee+89r94bbvTnn39a1apVzeVy2b/+9S/38tjY2GTXjjd9+nTLmzev9erVy3bu3OmzumZmu3btsqCgIJs5c6bPal64cMH994MPPmi1a9dOds1Lly5ZpUqVbMaMGcmuFS9+n9q4caMFBwfbl19+6ZO6n332mblcLps/f761bdvWhg0bZma+eV+7mwi3qcSSJUssNDTUpk2bZjExMbZo0SJzuVzWunVrO3z48G3XOXHihBUqVMg6d+5se/futR07dliWLFns5ZdftrFjx9rzzz9vAQEBNnr06GT1u2zZMitWrJgdOHDAvcwXL+Dr1q2zTJky2fvvv2+//vqr7d692+rUqWPVqlWz//3vf17X3blzpxUoUMCmTp3qPp8xY0b3m483oqOjzczs/ffft/vuu89nAXfGjBkWGhpqmzZtsrNnz9rx48etYcOGVq1aNVu0aNFt17l+X9izZ4/t2rXLQkNDbdSoUda7d2+rUKGCtWjRwr7//nuve423YcMGq1Klik+D3fX704wZM7wOuNffD9eH71q1atmbb77pk17j3YmAGxcXZ2fOnLEaNWrYtGnTbPfu3TZ69GhzuVw2evRoO3funFd1N23aZCEhITZy5Eif7Q+bN2+2e+65x/773//a2bNn7cSJE9axY0d78MEHbd68eV7X/eijjywsLMwWLFhgM2fOtAEDBpi/v7+NGTPG65pmZrNmzbKsWbPapk2b7I8//rCjR49agwYN7IEHHkjSc+16kZGRVqlSJcuRI4f17dvXvTy5r48XL160J554wl588UUzu/b6s3fvXnvllVds/vz5Xn3QuXz5stWrV8/KlStnDRo0sA8//NC9zpcBd9asWXbfffdZ9+7dfRZw4/vr06ePtWjRws6cOZPsmosXL7annnrKlixZYmZmBw8etCJFitjIkSO9qnf9a1WnTp3c7xFxcXE+u38jIyOtVatW1rt3bzNL3uM2b948c7lcNn36dDMza9q0qftDj68+oN0thNtUIDIy0rp162YjRowwM7N9+/ZZ4cKFrWXLlhYaGmrNmjWzgwcP3na9TZs2WaVKlax79+720ksvWf/+/T2ua9KkSZYhQwabPXu21z3Pnz/f8ufP7w631z+hvv32W9u0aZNXdadNm2YlS5b0+PR85MgRq1mzphUpUsT9opNUS5YssfLly5vZtfu3YMGCHqO23vZrZvbXX3/Z9OnTrXjx4j4JuC+99JLVrFnTYmNj3ffrkSNHrGrVqlakSJEkvenG7ws9evSwUaNG2ahRo9zrvvnmG6tbt641b97cJwH3TgW7eMkJuJs2bbLKlSvbM888Y7/88ouZmTVs2ND9Zn758mUzM4/73Fu+vh8uXrxoFy5csBdffNHOnj3rXj5hwgR3wI2MjExSzT179tioUaPs5Zdfdi/zxf4wZ84cK1mypEVGRrofuxMnTli7du2sVq1aFhMTk+Saq1atsmeeecbjg0hUVJS9/fbbFhQUlKxR4aFDh1qNGjUsNjbW3e+RI0esSpUqSX6uXW/z5s1WtGhRK1eunPs/Bsl14cIFq1SpkvXs2dPOnDljPXr0sNq1a1u+fPksV65cHs/tpLh06ZIdP37cmjRpYnXr1vUIuGbevY7t3bvXjh496rFsxowZVrx4cfvXv/5lv//+u1e9fvvtt/bBBx94PEe/+OILy549u3uf9fb5GxcXZ127djWXy2XZsmWzYcOG2b59++yVV16xVq1aJfk9YtGiRVa7dm1r0qSJjR071urUqWNt27a1ixcvul9vvPHmm2/a66+/7jHo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", - "text/plain": [ - "<Figure size 800x600 with 1 Axes>" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mh ux, hk ghm mh ux, matm bl max jnxlmbhg:\n", - "Paxmaxk 'mbl ghuexk bg max fbgw mh lnyyxk\n", - "Max lebgzl tgw tkkhpl hy hnmktzxhnl yhkmngx,\n", - "Hk mh mtdx tkfl tztbglm t lxt hy mkhnuexl\n", - "Tgw ur hiihlbgz xgw maxf. Mh wbx--mh lexxi,\n", - "Gh fhkx; tgw ur t lexxi mh ltr px xgw\n", - "Max axtkm-tvax tgw max mahnltgw gtmnkte lahvdl\n", - "Matm yexla bl axbk mh: 'mbl t vhglnfftmbhg\n", - "Wxohnmer mh ux pbla'w. Mh wbx, mh lexxi;\n", - "Mh lexxi, ixkvatgvx mh wkxtf--tr, maxkx'l max knu:\n", - "Yhk bg matm lexxi hy wxtma patm wkxtfl ftr vhfx,\n", - "Paxg px atox lanyyexw hyy mabl fhkmte vhbe,\n", - "Fnlm zbox nl itnlx--maxkx'l max kxlixvm\n", - "Matm ftdxl vtetfbmr hy lh ehgz ebyx.\n", - "Yhk pah phnew uxtk max pabil tgw lvhkgl hy mbfx,\n", - "Ma'hiikxllhk'l pkhgz, max ikhnw ftg'l vhgmnfxer,\n", - "Max itgzl hy wblikbs'w ehox, max etp'l wxetr,\n", - "Max bglhexgvx hy hyybvx, tgw max linkgl\n", - "Matm itmbxgm fxkbm hy ma'ngphkmar mtdxl,\n", - "Paxg ax abflxey fbzam abl jnbxmnl ftdx\n", - "Pbma t utkx uhwdbg? Pah phnew ytkwxel uxtk,\n", - "Mh zkngm tgw lpxtm ngwxk t pxtkr ebyx,\n", - "Unm matm max wkxtw hy lhfxmabgz tymxk wxtma,\n", - "Max ngwblvhoxkx'w vhngmkr, ykhf pahlx uhnkg\n", - "Gh mktoxeexk kxmnkgl, inssexl max pbee,\n", - "Tgw ftdxl nl ktmaxk uxtk mahlx beel px atox\n", - "Matg yer mh hmaxkl matm px dghp ghm hy?\n", - "Manl vhglvbxgvx whma ftdx vhptkwl hy nl tee,\n", - "Tgw manl max gtmbox anx hy kxlhenmbhg\n", - "Bl lbvdebxw h'xk pbma max itex vtlm hy mahnzam,\n", - "Tgw xgmxkikblxl hy zkxtm ibma tgw fhfxgm\n", - "Pbma mabl kxztkw maxbk vnkkxgml mnkg tpkr\n", - "Tgw ehlx max gtfx hy tvmbhg.\n" - ] - } - ], + "outputs": [], "source": [ "cypher_text = encode_message(original_text, random.randint(1,25)) # If you re=run this cell, the key will change!\n", - "plot_frequencies(count_letters(cypher_text))\n", - "print(cypher_text)" + "# Your code goes here" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "3ed45915-a7cf-4d93-9d95-cdb591a45771", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Decoded Message:\n", - " To be, or not to be, that is the question:\n", - "Whether 'tis nobler in the mind to suffer\n", - "The slings and arrows of outrageous fortune,\n", - "Or to take arms against a sea of troubles\n", - "And by opposing end them. To die--to sleep,\n", - "No more; and by a sleep to say we end\n", - "The heart-ache and the thousand natural shocks\n", - "That flesh is heir to: 'tis a consummation\n", - "Devoutly to be wish'd. To die, to sleep;\n", - "To sleep, perchance to dream--ay, there's the rub:\n", - "For in that sleep of death what dreams may come,\n", - "When we have shuffled off this mortal coil,\n", - "Must give us pause--there's the respect\n", - "That makes calamity of so long life.\n", - "For who would bear the whips and scorns of time,\n", - "Th'oppressor's wrong, the proud man's contumely,\n", - "The pangs of dispriz'd love, the law's delay,\n", - "The insolence of office, and the spurns\n", - "That patient merit of th'unworthy takes,\n", - "When he himself might his quietus make\n", - "With a bare bodkin? Who would fardels bear,\n", - "To grunt and sweat under a weary life,\n", - "But that the dread of something after death,\n", - "The undiscovere'd country, from whose bourn\n", - "No traveller returns, puzzles the will,\n", - "And makes us rather bear those ills we have\n", - "Than fly to others that we know not of?\n", - "Thus conscience doth make cowards of us all,\n", - "And thus the native hue of resolution\n", - "Is sicklied o'er with the pale cast of thought,\n", - "And enterprises of great pith and moment\n", - "With this regard their currents turn awry\n", - "And lose the name of action.\n" - ] - } - ], + "outputs": [], "source": [ "# Decoding\n", - "guessed_key = 19 # Put your guess here\n", + "guessed_key = 0 # Put your guess here\n", "decoded_text = decode_message(cypher_text, guessed_key)\n", "print(\"Decoded Message:\\n\", decoded_text)" ] -- GitLab From 284389a7aca7e5186af581b4198b42f74d98fd29 Mon Sep 17 00:00:00 2001 From: Markus <m.stroot@iaew.rwth-aachen.de> Date: Thu, 27 Jun 2024 01:07:34 +0200 Subject: [PATCH 13/23] Small changes to Crypto and adding elaborate ICT exercise --- Excercise_3/Cryptography.ipynb | 3 +- Exercise_2_5/ASKnPSK.png | Bin 0 -> 14077 bytes Exercise_2_5/Exercise_4.ipynb | 362 +++++++++++++++++++++++++++++++++ Exercise_2_5/ImagRep.png | Bin 0 -> 5871 bytes Exercise_2_5/QAM_Amplitude.png | Bin 0 -> 16144 bytes Exercise_2_5/QAM_Phases.png | Bin 0 -> 20935 bytes 6 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 Exercise_2_5/ASKnPSK.png create mode 100644 Exercise_2_5/Exercise_4.ipynb create mode 100644 Exercise_2_5/ImagRep.png create mode 100644 Exercise_2_5/QAM_Amplitude.png create mode 100644 Exercise_2_5/QAM_Phases.png diff --git a/Excercise_3/Cryptography.ipynb b/Excercise_3/Cryptography.ipynb index 11f6668..96b9a4a 100644 --- a/Excercise_3/Cryptography.ipynb +++ b/Excercise_3/Cryptography.ipynb @@ -254,7 +254,8 @@ "id": "03674516-86f8-42a3-83e3-5ecb1c376a30", "metadata": {}, "source": [ - "<img src=\"340px-English-slf.png\" alt=\"Letter Frequencies English\" width=\"500\" height=\"auto\">\n", + "<img src=\"340px-English-slf(1).png\" alt=\"Letter Frequencies English\" width=\"500\" height=\"auto\">\n", + "\n", "This should look roughly similar, as we are using an English text.\n", "\n", "Now we use our encryption with a random key. Can you figure out the correct key from the frequency analysis of the cypher text and the standard English letter distribution? Try out your guess by decoding the cypher text!" diff --git a/Exercise_2_5/ASKnPSK.png b/Exercise_2_5/ASKnPSK.png new file mode 100644 index 0000000000000000000000000000000000000000..82276b78c65e794f7f1ecf37b12834bca063e287 GIT binary patch literal 14077 zcmeAS@N?(olHy`uVBq!ia0y~yU~Xh!V5;L_W?*3SJ#bWjfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*`2_fcxH8}e0rT<8W04KTt0e@lEEeN%3k4Bp6fri2%*AaD z-DL<mn4kh8olK-Tj7$uyTnwTb3{pl63N{R?ZVX!f4Em7_rpXLexeWH@3@(if{!<x3 z=07~7mc_upu(c$}FPMRajgyOqmycgSKv+afT25X;Nm*50OGi)Nz`)SR)Xd7p*51Lv z(aF`#-NVz%+s{8BFgPSUA~GsECN4f9Au%aAB{e-GJ0~}<prEL@q_nJ}s=B7Op`o#< zxuvzeqqD20f8wOcQ>IRvF>Chxg^Lz1S-Ncbij}L^tX;op%hv5XcJA7}XYaoK`wtvE zdhFz>(`U||KY!uU<ttaO-MDr8&fWVD9zJ^f^u^29Z{EFs|Ka1O&tJa&`1$M4-w!2| zo-;5oa29w(7Beu23xY7?DYeh`3=GDVo-U3d6>)Fxb|;I3?o<EpiBm8|O)!#kh50Qj zBkgl7?K)X(A#6+8m&B^B^ZPK7mG|C*ICq(z{vQW^NSu%ocQxF$X2&GCJ&$^RMVCK6 zcX;pL{<oIP>*l`W`@3RQaH-$iRqvn2?XC+oD7pIc>iW3aRi~JnJKCQKOtmmN`u~{p zAHjwKmrkCd3@%B1@5lEu>JBqAyfjRyQ=ZWLHcN5q?6A+9U6*b&<m2Tm&xyWz;J?e+ zLxmluzGPWtC$Bzoct*?b=URm|wH;=!RTJ&|UBtggUyc7fz3``zq`T;c-`75Dc%~+& zw)ALDtmZUx%j(J-OXe@Dvgnx^6K#<rW*{#p^WdRVXYJ$THa_i}ZF;T>$}Mx964Rxe z^6`JJ>c*;w8{(O@k2U4m6!!T)*Ir&BG5dDq4L^JSWasx~(f^$8WIJB3@9&cFsDHAM z?bf}g+K=N7G0ZamtfuvL&w7cC8*a=BGC%Hl=7N63455=-cJ}(5`%ut$Y_0DZwTc}M zvn4wncQc1c=@pCYPI?`qHse8<wWILs%cYO@2maF%zQ6p!OXe-p%|6eN40*u7z)*DZ zhTl53nuQ<b^*^+3H2&Y(cKymfc?*N3pUnAsR`wMqaGg>r`*G+->Obz^z4{OPAI-V7 zV!wLD(dD9_eP`X$UvhKCw=0d)C$L$(=&Qc$^3m?Uuuk8%^S`~EAN{{pBr{nr{)YJP z_Xe@k4c^^PSe3iZV!M)b#PuuxpDHw5zx8byN8+RZ1s9I`{XFQs;``F83ihAmo+h3> zZPT+TTXx&KH=DFS^<RwLzoC@*+l7iF@}j$H7RLBT)usM7VNZ08aZ-G=OZYGMUhfJC zzwK&I6Ki(qC9+R^w(PUG+K126&I!5QEdCl^ny1TEHzW9azD<tiztCgSrEeEG{n)zd zvbfmpx#a=L*H1QVzV~vy=&rwg;h8?0{)vC<nmXg~HKn`H1Pk^xNpO@fZ0c&)o%<}& zfLU(s6N6O+f7_0Vs|D=v<@;n{*LME+ZqG%G&N9>0-$%+FTkCs1zpA-;hwXK>;Q5~o z^4|7&dkc3i-Tw6Z#5<SNQY>bE-Ov4X>XY}j^Cro&+4%5ZXyf1i&`|l-m#It)4S!Dl z<8zE_UHVc-e?`opAl<2k^VTg3{<=r{oU!_6?he&64L$ma_LWzU=%+<qD`7NiKBd%t zIMV*e!D+{8Bb>e`a^7uMEs4K2eZsHRax>p;$&r}(Ze^kbZ<>AkjY}<)PF<cdV|qaB z(w<A9I+how7dS4jUYW@${_WIu)n7tk`i~W!Zdm%V#Y^?pvBIiM-G$G6ryY4d$!^{R zuU+0dF3tX8bC_R{Pkp6Ti0tk+@8y@DSna1`BK`JP*-Wwjq7VOWapqll$omIVZh*74 z%fD4h{e?f5Bp%*Xp!@fQ9A8iOYCiGWQ;zIKji*oA2Cm`#t2*VgY=!NDi$B6<HY7zH z@~%G?7+&<+Ib^2iy7+YNDsKxzJ1d`~3lBax&-J?Vao^#9l46O>Hvdl-I(BR`dAR40 zv+$N_AME6o%{nJ^@95!@&6}rjrSX+i9X0HA51fCt#++Z-Xp5(A!1Ck$<tZi25|X`c z?^hN`^D7%qamg-yQF*#@#)b^<2+6PCDy#m6r2L%jyJX{Sp<nzemhyk|A88o9`k?<| z`*Fob`>*;xp1A#>U1gomVVg-yGQ1;ReAIjQN37#Z$3DB5(}z!3i7fmRd*C0d&D*su z?W@-?FP#+A>Af^^Uc&LEHa#z@<+dpmTig}@zqr_G*Q|EQvN`RNWqs{}I*$@>om_s+ z{oy69e`@^9uYKRIHoSe~m2Yd+##<IU3o{p7oPOo9^aqY}`xCs5t*_3OTK3w!=*HE^ zexLo>Hf*kuVev5!`b$2&nEUAPTB)3}#N#u|D^JeKS$H?g!s}C?%v04}C-{w)&G>k` z_ey`pRuv|2#b%-QIo;SY;=rUDt1B}7Y5rRIySsufGu>NYw|VK$ZJR89TP?Z3d$WF@ zI0J)29PcXOZk_qDE8flF``02T6S!^q`SXd>E*4z&t~YYGOIE+^y<(o?l%LrqV51or zA{YBT6RwzFk#!<F>t@|Yj=*d2YbO1Cy@;uO=90SECq4<SN<IB$X)cHQ<LEUpItsml zy(v4Ft9}1+det&kpOcS2DraBy-I&Sv_|5SX{X30%_wU`B6?LybAoOd$%$CVN=dFlv zxW03L1GDPa3meLeHZ(l4-xw^BUHo8DC+nNw@(Wx1lGVflbfRu|Gu@1Ey?XiB<~<F} z?Jiu`e?8{jvA<z%$P=b-QT0X7r~Jv-+mtD#zW$cKtxXzlr>f73nF)u#BrEBP3;C*U zs`-A(clDQ>QuC60--NqPza(j@bIqtiw01#T*@d1M@5j#777}5mCzS7XE|!_0cKy7> z^bLu*0*Rl)Ox~HQN`%%I)_y%ypZ>7!!a1d5&;H!B&v)OSIsZpNsp0)+iOpi}MoBO4 zL_6#>w?9%iIjlXa|GUMGhP}C)E+sKm|6<Q9NjkRn{^k{T7ymmK?{M$;d7lpzzeFph zMe8N44h^~XK*e3}g{-{n(u-#AuV-y<xTnW=*WmWIZ(Fx<ztH{WtgiFv);`naUztuB zuQ>kq0;hjP$diJF*SJ?~xv8@>V7cYn4Gr^bmK7d+YLm0_GE?58#9MP8Bzn&kyD)L; zme1Vptn?O0-+P>xJy-lftH`?NiPG=VH+T!}(s^Jgr{;AwDM;IUI_sMqja}Vg`G@n^ z&#sJcEv@=f_FKLz+QB$n*mPZY+~LDzyL1!2<nt}O^eje?@2=PfEjcyMeKH2GCJRKx zwP#LglM1=nJ>$^2|C`rwXZ$ViKKDiZgR$JQD~@v8u2wPz|Fcsw%(vckHsLv|h_v~~ z`d68XnJVAr{lAj?`bw(kRPo2RbmpJT>$+3;$tLMt-2(%yMf;0N_KAEs@@C)vH`^v= z?&n??cdXI1i1qP?xp}K!Bz&(wBxjiIUp9NMp7cz|jT1fJugy<7w(sigF0Pkn=U*!Q zwoC89UYi_62UeAJ+21Fx<G#@tV|CkmM^k(5OMQi<4|I>nmP9-3xA)BsS)@A8{O(5g z!biLIUfX(`sccsH$Mi@4ch8%sx;pxCS@eOWHaV{UZYPP#zWyc~RvLLAYW@n5*C8%W z(^-8=i)!>gZRpKgy@L7O190#*vQ*uBZj+<SEcxZy#|=ySxL>$1*}l(|+cu?@r_9G? zIcteZ<J{7S17fwpmtU3J<SabPwCmfA?2VhYM&7@rv*5?=Y5j)ILFM{eFO@OIY9F{c zf&0a+Po0tPGJi7t6XVuc@4}H<Zq;)wZD(jyRQiOBjFM9uRkp2MHI3Wibqp(4(zN-H zHw1RG)+9~*b$eal=9+&s^Y=I8{!4nryZZccak)zUm;=JHztwg<`26hi;b*Kh`R43? z)rJ4G*g}smUE99)%F_7R&K>L3ghDHSu2Y<zr^1nRl&ALh6S0l?cM2z*So`>#LDaiH z#w}V~LrrFj<)j#`e7Z1dS^{HiJ8Oxo*oD#vhwF*RoYXo-Mg|6koYOz}H7pg3BNk;U zMOmuZMcD^Q2c0>;faA(>2CYk$vPL_)+9zbaHI7)T)T);;+wrFh+mZ{3{I*{LzAkL9 zV7b$xy?dQATWmYeE<VW;S)&(LDHlplEZF_0JYxk<RDHXW%Z1nXD^!g%n#9a!IRE;3 zS|&{U%D1Vu6RKV<jXW{`@RQ(ASGS4G37K~O#5ys}SF;%o=uNdRRWbGo`L?{Vxxfx; z-s=gD*A<(wScFAlgWS(Xo?YD`=7BR08eQCB&wEFyC}PDazU)nhc`Q7?nth4C!R!|# z>sENZWwXmSwx`zq0j+tHetzyxaZ$DUvdtx<Z8ImxGVgr0LT^8Vm*)~X_jpQu-sAj< zIm)Y=?YB+7Pu&XjLyp`l*B|^W|D4@7=FEfWmvb|@bxhp0M%B(g>~|~egYHNE0*-A) z5q}@2+6c|_Q3#4iU#Mxa>G*{GY<^~JMmHEFOXe;;CNaT2ThO=5crV9<gKXD~UhqGE z)jmT}p_x}Fy&#OQ)2lt>)_egDqZ<dJ*lL-TmQ9-DH2IUUM9PN7t5Pv5wfvVFih$TW z*Yx(RnL2&_^dG@Z4s6mEHziIaFmIPizEa;ae@5olf-5z%m1YSsUz8AbG5%-5-XSw7 z-1VQx)WfTSe@^cDBq8?mbEk~e#QpoykJQYwE9jQWJn`Vu+#*iD+)(A6DzDDppSJ9p z<F9{?e6_C{w}t+!$ei~;x?=9X8sp<X7jBy$dQX1Yc|)r+fw9w-XY#ttwmidl?|<hp zk9a=udQWM~oRyCmzsP6syZ^kf(QwU;dw<RP)*1VzTYk`bdC&WZLaJoVv~|x`Oja=d z%N47{ZalM|uZGLWW63-A?|Y;(C(D-z7cARv^|JEuO#6=>u58s$AM7^25+Tr-{)@}1 zg-6Xlb;7$x8x@+)Y_SQ<S`;>!$IF%Nzw+NHj}x5EY_TYwBPM;BXY&lluh*8V{b7%7 zo$)g6=lXN0Kle%gHq|f^|MoOCG3{2oe#Ts>lS;QG@6?8EDZG(x*m8b>#j?O=o=tNc zqx5d?IFan=I_u^7vcd_5Va65DuYbB6z_wR=b7Y&D@sD$hWm-f_ml@A=>Xuw0D$^oX zx$LDHpV5&xHd8L8Uq1Wi?7gqMCN&_vdzs<o_xBDvrrkKT;F_Li`ZD`dxAG56GxG4Z z>~P6mmMO_DnW)~}Z+q0yq{?{iOy!{eR!eet1V8GRw8bpB*-<4K^Dmum&T=d6mCJ+M z_Uf(l-p*xWF0(%W!GYR;>zS8*ex6&`*}S5}{O`=0eV>f$EX~}1OP3n|a0>gy(fx-v zJXAbtv6=mO$CO=?XFLR_T{V8^np|KWmAo(VjAP1)1^#=JolM(qZufm*KEI5u{M~Z} z<}K37Tdv9%3C#WHlfHyQb+Kf~*1G?39~XY_6Y8BQ7nHv%P*P;Kpy|m%HDitbIX3S< zu>EIK;f*rZ?c4X;mF?)6l*ggwZrK6b?gjize5<T}cILF@0g3UO0(rlA_;Q~~yO3}D zRyqFe%xTLHDprS|R8M+kKgE!<%~)go6G71m9j(1H#f%L!o-2jCpHq_NZ#2uXRJH7h zeYbz5iQwFGKBxb5`iFMRydgO2%z`uXpRcuEt28&>xg>4Zf-t#Kk*I0%=ZvG8?fxcL zyq&r4sVSe4!hA^^*_Uo=byFhb&#p}Lia7D$aDRco%x^yK(VbcR&C(MOM<1Qn5cW&B z$bC0Qsqv1-l6;3&+6D!m+h1?1en#1J^OKi%Wn7ldKG?B(LVWY(SDHO@yx&f}7`W^7 z+L;I0mH!zT?w1#tYQFN(o@)!XKjmN-%uF+Q#T9a!|JUpbLKi#iXSpw5_gFz{FOQqA zg2|<9*R?!y_f9fqT=ZJ#$5vn4!+c@MWT#%9ygx0>7fKhpaV<_SI6Ga&foIWjgCe%} z{vw8r3%D&fw6oak@1A2k@}yf=rbWcCc}oX#$JwtJw=J1yw8QiD2k~1U<)2yG881A> z#5MJx;y#Yr#Zt{TRvOLWy8c@;gsnZ5?R(wv<OvOellcEWo9N(_TF|6rf0)fA(f$7v z7dGy{ucrSny0|n;X3~NEo34KRa;_<L!vCXI^Y}O=RBuTwYHZGT<)7e@a>HHSsp3_} z;l<{EH?Ct!E3iCyj$zl_V8srl{6}0OFJ$Zk*!KUsA)oX*lWG2D&+CETgAcEhjB$Kl zpz=GdnBm!+#qmW~qMq}}E&Of4G`ny69^<8p&izSctB#gkprhMf^_o%T?W^FDB|l^G zV(#t^3;lk<<bGwL`Nd=zr&BuBvtE2rzW!;3Mb1+B*Xrfn`PK7Yr1ag3e7>#wdak@= z{nz@=KYM@wuKj+0-z@d!;3u{}cuhI_1aDvX`B%Z8Y59-+PFrooSlwB6sWEG|p;lK| zY7t012A2R;l?)6F3<`>${nOaZ6&w4UnPis>d3bkZ_}R`qHJ|I;2VoEIJyTt3?+Hb{ z_Gb(K!D*vn|D?Ndg^GHU^&ggdTJ|aLCOBOG!6`FAo?EzrnP2g&mCA-)UCbUEzj5wa z*!549FJu0JEK$`L4cj<HSUZGDW}cDvx)3`ZQq#&kGAs}@TL7}PoyCfevqVPdg@ww6 zLXQQHCpa93I0sE)_pzt#UJq9MVK^S*@yu84Lj6u%i)BtGYlJlJ8yvlSKvk*Pb)v(Q z^N}tlA+G;q)Qo<JKRKWJDb4Z8`9#)<2bhjOko%eDlX4-}s6O;#ynTOj^p)9}tBdSA zcy_G_f95~$gmQCU(9huMmt3waR%`U;(#n37WOh&Bt=?3J0&#+l!|7@gC1OQ?PSBlt zAnuOJ`vrktXPC@%_<BI1;M|Tg3p^H_k(V=mq!id3;`-MzC*p~p-G&M72Q6JE+CDj- zx{1w_g?%B@UA0f&nZGr@o5a6n{i@@7pIHjJZu~zxpZ$|c0mr%{JN)(*FkE+%T`t7& z&WTC3oyAJ;DCZJJz6H#XkPn*Y@F{QUO}l*EvumHMyrA=zbIv^Nvlk^g`R8$+y)@5Z zruqNHOVkcAW%@7hiT=xcZt^#luKyDb_|5To5N*Sv&AF$i{q7e3gs-)H2i%y#L+g(Q zrsoR(2s1r;oA>e>l?_rFt+~P)|Gux(aWss#6k5X-Ey&s-G$(x})9U>XCvrUbFH?O` z%9`_v$NZLGt2a+{IQvDhv3E`mx5@^T^pUfbRkK*xMv6};B3-{xHPI+)ex1sOb8$>p z7xZsinP}mWF!w1-m5HX^uVpVM*h}#UMWov{s-Bl#{8H$mP`#6YN5b5@EbBs<cZJrR zDROIeV0!&VHDF@&xk+Ak8H6M{uX4>%yBQlU)1{SFrQne;_bN-(s@?BWI<EYjaKLIe zXGn8&=#DVCKDHK?Ymt5lp7Yo*&3UdnQQlFpv2>d7iZ<^jat1E{CLCZ}x3#rOPfaM| zc|<f%;Qk*W#<9<&&RJd+duQ`5G$-4Y?Wxc7&SQTwD?>xFH{^87NljZQ9Kv?gC%nV0 zGAQon@^g!HtNxr2OiJSpec~Tfxq8)~onKDm81A-Ls_#0JaCPgSl{eMe&3<_b@qT>& z?n(aHf9FHqN$n}i*Z-gBw=%3ip+4Hb^XHsfJ7an~-l~7R{4>w8AnM5ZFDob76ea%N z`H*>$__{}ej%PmIKU(i9Ct5Z~@z(w+?nSQ8^zXVa$o}uM{&Y0U>mxk;VNcUP$9*{X z{-r|uPsPvb-y3aaS)J~?$XUNSQvI{~`Pw4|4+~$&Et)Iytoc^ms;M*8mz+*p#4B@c z<)4+S`IG!D9{Oh&%;+ne!u;>w`S_WYL0xy8<qNMY3D_?dm1%i>|1y7zQ#MoWuZq1q z{Xnj2`r>IJOt)`(#OpmXxb1fJ<MOQTDY4gfbjCef(c8x<qTW+7WpPgMbN<*{huSvB zZfB28ubQ!~Sj9|VCMD#R(2jny!YgqNGyhEy`^hMjaYgkDm-}3nnJ-trj5Kv&nta{3 z-Y`Qv_GF;@!L(nwQ>|1C3Lk&Yt@)(Qw~NE#^6VFGDi<1}n8YtX&bkr%VCFJsrN+$t zH&&~&a>{%a-qE)%U@;@h{FmnYg6C!!>6mif5lspfFIZMx^_yE?pts-8=j@c|_#K7u zQ9>4C%W9j?Y^l*rGXB@x<LSuM?t0s=?d1&FjAhl9xn4_cj7$G5eedJp&gAb`EaNj{ zrrIz4FT#DBPoy#Jw0YGer{CuN;KQPxJlm-<Dg{@f=RV}Q<@4akj~_o?ym-Oxa&+Os zg$EBZ`M=kSVLEP`Ut4CJVcfW{bkP?J9<3Orrx&~H<?F;E{S)|kRc9UG@;!O5G17FJ z?KNSKa2~Z;2P9_&9^SnBszPy&`iCcv<2G^5`M+}UH|E4+5q=NWt-oR_EXS>N$w&YE zv%Cv=O!^ahvosp-3CkBx&@2;PQMdoC`4oruudOXl2(9M4BfjLn3wL0;Rkw8DYR;Zp z3j))BT`adaAuyZM=JwwIk=YZ|XX!mxu+~xgu<S(imJ`N%m8zu!yE%LA&A6EU>qxCk zO50wRcP}s1?_=(rc`k<YmiGd;;H)!WCa#GM+&t|-^}hp-ELO&Iw+d~U<}kPI%FLJF z-#t=L&QUEWKK<LA`O>VHJyRE~WyvyKe9dS2_2LP<(}Z@MiDR0cwwgs(^}~yw=k+-p z^OsFLAo0R<(LEn~(JykdwyZv3{Wvt5XLg)szTH7blUdoZZeAPK$d#$wUgQz-arw+o z%UjRC=X5u36fb<RqpRk@j12D2KQFIkJj-(LuNM0{VM&=)w@%#ub=|VV!?^LLWsl;b z{n01pm+$%cvvi?iqv@+Ymd8IY=Q-SE*|%jT^Y_S;^S`ph6;EP*{`E8$PmRB4%(i_8 z97A?-o;hO{^7Q<lU<N-^n|gC0l?&>hm(LT=vS_|_cKO@`&y6<<Px(1HH_@i~n{Y++ zis@;~r_^vY+!tGBoMGSCz5n5X)PK61t8}ycKbj}^?n?A;FJs!gQCMb*dEC$3iywIY zKY4q-&csqEV)=csg|*AdRiho4UhAj??Em;B{nz2EG8X#voI0obo40rO-*c3-I+wxp z*I9L{!`j7ab7!twk=<VXK74tgTK`?4B%{U}<2`=@-oNkgNndvS>ec(QzprE#u*s=r z88!Z!x!h;Lvzg1U`ShRS$@@`z;!o_c!&eMvI{d%Y@3BB4<89rSw5o`jzxIFmO|=iM zUG=YP@f5>Z4))C<7thRp=X08;?aX|S1k<^iS9}*ltTXsG|9;v32Z7%I)Sfp!4hWjz zv|027|D~(8HP`39Tr`KXk9m@4#9!Y2C7mx>PR$EZy#20bma*=q@9PtvJE<7-zBHci zFw_1m&#SXr-W>b-Ia%>}QmEDCbel${`cDE*o8|ki`K->Xh(7jLIqCaM--Jjz`{`S% zjb5GE5>bC-y1l`n=O*WjXE{u@FO+*>o>XFG{I>q<<l9#*doRwvI4RMnvF_iKsWSqV zN_{Pr*3JxDeePxHqs8XT)1A(SE%?7IVCO@r>$j?2p8v94y!e65V$Lsn%edJmzC2%| z))z0r&AI101N+3AUJESV1bW%bV-pj)Q9Y~q#2eKB-esAcQp=iJSzhJu-;(|->c8WQ z#H;75HC*p{eV%#1UGAB}oS!UyUHz6Db$t)+<_Y_FLFG56&EBTw0*glFE6<O6Uz*^^ zJ@4j0$B<i`Jv+F5wi~!88<iK??+B`nEeX0W$+u|J^aDYeKDqXLCvmVwt^B8uUvfSA zF3Y=r>3mK>voENs#D_&bO1iQq@=oA3;fg#-cEz8+59EHbDOmf?$RhWDvy97<*#}ni zo@Y1AQYdeERN&@&V(!xW#R3!4nDnpuEKoOJq&iFY>?)mS6Q6aho_Rny+Ja;Cv;%@s z+I&aVGNb1BJ-K|)R>o!V%mZ`sz9%ic-d4rA=bZ?<z}&Me^LEZ+?#O$d$ftDCTVdOR z!V6ihYgxqNpD>ij+&<<g62<Alc+7dZY^hMi@j^a_^Xk%;9S-V^8V7b{Y+2&QRR7bG zeZlL~rZO$dCpzq!z<gn=Mir-<|ASq{G7b9{AC_qmvu(V=d`z<_+s*I6k;^g;GTZ7; zIYtBuS1@uJ#EE=dm2!pUQmKrC%_6zuE<O*Y>031Hu=#Dq{?Nro!EC|D#lA8vLb{F5 z<j>D%pSVgXhN+$F)x@ZLyXD6e;>>?Z&fzTG?zw~I7r*MA4&DqSzP*a}*>_u;IA=TT zeCzUW(x<y|A1CH8RUbY6)rM{3;@y+{68hbvD_Mjb?7b}-<^E1f_F(yIa+BrUBL<Vm z=|MY|%d>kwNN{}fn`P1BERK^uJ3SKo{qytl_uqdO%i^7Ib3fynWj0e=pZ{9YTUC_4 z*nz)*YnsFVgB`pR4*cLPynT-Q3(r=A-wwaT7ae@`;l~vpRqpkj9@>TL+z!tFFRawK zWompGL+7ORiZg6aE61|>J#Z`hr?>5r4cp1U_Y-gUGRAj{nl$F0y27j6$o4~@DbmIN z$KqHPABDeub$!Z>Y*+3r{rmBH)&<uEEO`%4&lmPs!1!6;dH-a&ug!i;Dj%3ueVsq! zV%0VsmdhXXI?GqQF5a+9y<pM3`pm8^@jtm@d-<-%x0PDXeXwF~9%qdEi~pHdYfD-d zU$avGAl~xt^R>I~?+dpy?0R-rv$6cb^Bwi7yzdr$3gVOIS$Uav>Vcxw&8L+f{yTdm z!vBj%`)7~22B%o2bsqbh`FWkS^N#<vv2x10W;-u4(h!RHc;7Lw{H35(>+|*{=Upee z=*J#bo^&E%;Vy&v-RA{eYwN^R@;-YmdY&JBCRwT3-t5WyTkd|swz408PE0uS%=v!D znc9ki_kFxc9$)Tnv-$AkWxlJy=YlQI<C}R`=kKq-|FGQk)-$!^?%UR%KJ&ZylWXZz zhwmKeop1ie{+Zrre*Ed=6L%9r>)h&Gm~N<iRzJ^tbi+>@fjJ94Enjz}!}ei|J+DmA zig@m|58BJpSF$wi#?`+ev8RBqs{}C$)W1W*6Y`i_u5V$!(agoNfm4(t;c^Y@v?m{~ zc`mxS(avz!H-U?HZg_olXP7YM7}p#z({QQTlU+Sb!lVQ*&iQ4`;Ng+XI_b{O%6S_0 zeMh!T;$l#c>=iw6HLU-L{30gCNmn8onYA2PnPv#DWx8KApPAu;&`PHJtHJ`C7z#Ur z8W%AHHZg4M2xwddVw4pyE@ENKnW676MWI1A)W$&QfKrG;gYOClhS>p)3}y?N7;~Ih znQpW|9V)CPa6k>8f?ENtZkB7p9~fK|XlIzPz{vCPKaTK(K;PA0RtPe91m(M4jSf7v zifQM+Ur$*WJYx38H$U1C9HMajzQTV=29@>kQ)PKW|1awj{K}pX;W%|c(=X-?4cQx- zvKKIjeK@%w;DIJX0@wBX`&arON)2F`yyIWn-YijjR|bh|@BeG)TOT`dpSk_2M3%sT zj(b&qul_pHvr2P?BLnjl)eBL_1Kv%2)_b~hhXz-|p$9)|*e^t}c1eZoy~1!{Nfj$o zLnYaMCKxCrDfrCww60G|Yr}S%6M_sX87rJzMEA2j*WR#SN9~e8Kchp@vDA$}O;3ov zxGvxOZG|C&$F&t&7J<#Hn0`O?0|ncK4O&*eHd@8k|6ylHV7a~^zW%U{AVZJlsz<^B z^$cPnfB(wsH8Mp!xPG6170b#K!i)zv{&Q^k)W0e`Krl<-fXur6j{i)ZdLQNp9N_t{ zwPMBoU;3YZxH27>vhe4x>^D=FWeKz|Vqg>55&oiS-pw5<TnQ1*tV|7sh|p73Sj5Q3 z_+<f;vIDDAPC%pJ0wzVX6$d!7L?e`<jC9>vc22!FL;hma*K!6XM^-n5Q)|K+P4>F5 zXs15){oa{zQpQW*kOQmRg@DHPD=d<}zb-Nap6q8}f(UJ2#cA|tmouxA#)<<RQd$AL z%%Kl>S6eV-G;sAOc(L9KSi6YjVa?AK2SVTf?^+z;vce&-LBlaaQC(Ey`u`uR3~E?c zF}ZLa`dJjx7-SPFv5RRZLtv9*VX-6I-;d_g3#Xl(3CapOQ&!h5=zS%uSM9MX>}tbu z#vet&jnh`G*OS-fO?;ZNcSB6Akd{Ey!Ky^AC@H+u$(vP%4%}N_9iGV(qOfJsVXh|u zFJ`OFn*4po>;|ruu%g(;c{SU(??0Vq0h0dAB{Q>rS4&6DWX`uDfsGfu_Gt%9n_IJQ z(so~&zE$jgCzvlAN*>`8<yiY<1JmrD6(_ShmxU^HB>6n~#G@q;buy84n##|D^S?em zTVf#_GFf$_^^=nuomic;E!Q~kJ>6WEE$-yXYW8vYF>a6%+nKI@RFg00`g|}~%R>O9 zznHbEHpwTJE4Sv-)*GgeYy^5vma?uYnjI|e{Iu}J7mrMzDM?QLbKOBEu6Oua-4b7@ zecZ+J(vxjVew|prv`}=7c&FBs-<DY!FYkR)aA#O?fQ2{oNZi&#rV-gM|81J#;rx%| zNpN9Ta~s#2nG(-9l8p7bd$TX(XYT)(vBka5!A|t4R={e<bqD5gS_+y<><+xSZWUXq z_xICtm0sz8Uv?$y!Sw~J9QOaqVAFPEY74y`v@mMzRr&vnPa^iRxw0<$Cv?p8NAs^E zg=`vIrPlnjex<J{zCNz}_qX5f-+KSoU9$fv{O|ed_T%4s@9h8kt#q~iv;Az9Pp>c7 zpXm1YXv)!N?fhqJ7T=n(@9&2%2i3pZZAd=dHvj+i`mgF2^XvB|p6+A+W>@*)OZ)v_ z!TV-fe);fB^pAae&Bttkuj0+Av*+7s&i?e}bN`*Pw@LFNf<vCy|J&BrWwSBu<JRrA zpZ;Y2R9F9B`Ppb5$Ib)K>%YEUByi6)I&P|O#k-|<uYZ`*dSz+)DxR>_tfF(nn@z93 zse3u+&*$*%F-L+GPCt9?@5Jj?@b&R>m&>v{e+S9suMDgIliecqy2kX`rQQ7<`-@&} zTwN(+l=<&h`qo=NZnLm#{^xozC4JtmKKI+7);FE{wfgTTsW0N4ujg4Q|GU-wx>97* z(ud#Kcg8JXJG|qyMc~dIQ;u6nO?vz4di+|ZY||U>0=AsIlr;0jk60VF$ctZo&)*-n zfQ@-)!T0Ab@9!Q=b`;6l>-1VwqdKkqrD)ahYM1%<%N6?_*;e!gZGAm|>sP0%3RT%9 z1@|orFMa2h>s%1m`0#Jg9I1J```r)JF8+F7{?+TFBCpo3Jw0E|YGa?f(xsISnRhuC zE!TfOao4|phaUW?6T7o`cifW$rSAoNU;Iy#bM{^@@SOj>&W=CI=e5!;*w_~`S?~VL zy~thvfuQckEnissg=!1c`#p>oF`braZVqUajrng_ySFtt_v6+t)7HOy%yj$}%f3T~ z7964)E3GrdznqQ!V!cS+qR)Aa?q8OR#oZxG^m0~n%xU48a&G;ByDs^9&n@H(w}1I$ z-dWb2xVo3!f<;tAH==j_{H2?vE&F``=<fZfb2e^$UG%G`nh)ec7F^jPm9J`bAaRaR z=1b<HW1Sz0TXqLD2063#seDa)y(4N@z`7r`-nS1su5=D)ob<|3w_N4Cpz2jgt98?! z{noZRsCQ9ug~Q492j<Hxy?NC}wXSe$$@w!^jvP4x8fqxmXkoG>?XUN*_x~IJOUO)q z%=KnsRqMaHQjuSpwO{A6wJNTZc=4>&KqxD-^mcyXMM<k$AMIQ{R?i7jxWDe6=N<K6 z&aEZu=Uh)b|NEtm?eWP6R974*lUaE{&T{>#;J@dy-alcR{$vZ&?A%b*=^tK)Ov=i% zd@Wp8A$~E;o+*6+)85zn7f+X2=kW6~OZbB4Z<oGb_gvsk1DB0Uens;pCgHldfkC>u z^V#kcR9})V=}<0kx~KiYZBg&M%c46zd|T4%VqV0-ccPNj&OQHB<7v@~edaIAWgLG! z-NnT1GCRxh!13v>=^K`s3qH)bAX>TZK>EwvKBKV4dEd=!PYW)IsnagFC~i{!zxw=x zgoP76=-Q=4S8>-qynm2ebNX$rJ$)zM6hGwM{^hDmto%z}%?a1J?)c3=_UX^k2R_@s zu+G0!#;16+D5}x_di@czqcz_C7cR><Rz2O!)E`wbb4%+qxn+xG9J8KoWD=jReD-;~ zd*b4y*DvmDT`$}^<zymj+z-{Y4=<=_>+Wsacf>mWl5V@`56i!klo!9*@<sneai7B6 zPvMR8PxLJii^zJ}`-Rheg4fQ~2Of(&`&)0g>FTBO3x$0Oy`RDwkH5GsGc#@N((M-w z`xIJ>!W#9}?*86vTdf<rMBK9J%gJ!ocS{b-%uL_7l>f3{pF(L-Xk++g$v&M8H!r30 zd~a;cYddC{5u@)WywCOOzF;$J?b~Y(ynZ3#K7p<I(?h#I*M9u`>SSAO`LJCyvTVY) zf|TZ~i+gQLCMbI}#{EAlzbad0y|}CC(n&AH`EnL2%S0w_W!kI!b+)1+>#x63I-jZz zex3f-_Ce6Ed#{S`z72b@^#0`_K1I<Vyf)5Bdo@-SovHX+d9SW&g0l6Sum#^0-ah9D zYRdkg|8s?XzU17;CxlLmzL>i>RmL&u%zhii-(S_=pPZT>yZuBN>$_urcfAb$;LpDD zz+=g4>7SQ794%w5N?*~h?7_ZIW^u|sHvUU|eK{NB8m(VQ_9^i0`1ddB>|uVvdt6p$ zCz@W<zF_UEZNc>V*VEs2PtJcT+Izy0*UqQEAf@*&S51rDGY*~CYp=%V?hTMl+7#1l zT%zlK?Z)~8+0yqnvWQ)My?$TZ3iFl0mhZ%mFLPP{xA}rd$N~!<-yb_42n0A@k-r{Q zyH~>h&s)cDcf8pxHmS3URy4eO$`Pc@`nr{I{Y71wo0FTS?Q4yD%n_t4E?Qw&dwQa4 zX2#3>mq~pJx<!GFuY(GtGBz%Kt^R#^uFWb5t5dG5dCS!;H=PLc<_~=(zH|PXy=PqG zc+dagy_t6+hqX(zKi}!w9>J;u{B64H%BMx$+JEA#=?{k96O8|*Z2m7`*`Tpn^u_w* zKXuaz|9=a4SDElqTs&LX_MQH=H3xM!z1m?O@;1xj#?+g&3icchwsSs&{@VF>p1oM~ zt^52z2Y*}oUVGL5Un6hzz5k-_0zPTl1$EK-eAfM!L%+#0Cv08%*Ux{;)P2E+m%Q>1 zNeFciZJY3rOT=_Vn7NddbNbT@?{X(hi@tTAMbmSibzta%7A>9=pQ;YN^g7eO=Mty= zpXTLHug3o^`@!9>_O5^b&YsOYvME*a8Xub(w63k+d;1>yuj5aGCix!x?GO^55V`)q zuiO*c@}0Kbx>O_eC))JE>)=iS(T-Q#s<%Z?d@T>Eopg8hdYx@w{-mzpEt%2JDP%3~ z^0jr!Q?4h!q`!T;$gQ=hih0S_Y0qZcKTTaByCwhMuaKha&Wb&6!XErdX0Ul*cPsn9 zT8g*s+1jK(rw>%Wth0RJd%0y6TUqK>CTTh52bJ4bZ&x$<dfw=Kn0NQ#b3aq<JhuOC ze6zlxZsE!aSGhu#TW@7vd-cmgsa5|Xw}tI7+47}*%PeJ&?loZxp7Zuyx3;TuJN-A| z&Mobd%NH)4erepNV7e)~vG?2Z2dbMiGhWVRyDw{~&~KjgOwIknmIr2^0voe4x|FMf zE?f%U(zf`?NiLnMKBtWC9II#Y{S?@E&wR@a<?J`xza;%?Q)W(KEz<aUb|FjjX-`(U zMYk<B9jo)c@78W%l;Fr(rMk$IZ~BVbM^DyzSJ>Py3TmAFva)Z@#`~AfUry`eiHK<2 z{AfW4>-H}D8M2zaopT@E@iJxo^gtx`=tSLX+8?y6j!xw46}_=N?A@0?Og1hi%a}y( zol;D>7gp7%9K9y|0r!@v%EBqEW)>y}_B+cAUR5SpxlgE7e<{_cvoW^u`UTIvo)zzz ze=j?lnEtjRcn+W0!$U1^Zu{sLrgXmLsyX>2GU0RJ3$Ma+=5N~<G5uW}cw+A3Y1_9? z(=KSRdvK!X7}pn@O1Twf&9yGYTeBB<XH*GYcmAAgyZ78g*=gDzN^c#QD0x<NMW5Z( z_l-rn_KV+9Q<7<Uc2ec;*@>cM+8^?&rYbv&g)ETzUf*{|t<SU8LhkJJ?tdY#=jXOw z<%;pE-`C;H5S_P7SmtKJRwn-oXJr^~e3r01I+4{(`-5gxk21sTKB;{&7f&Ry<}Fw( z!x*u(CquLS*v-`kmb#p_VA+suJJr(YTpa7POj~z`ZMn<(EsV}avDT$*Gv;w{FTYqV zBbm0E>Hgx~7EB(^)h}ZE&TI;4tY1)V!Q|2Y`vr%)+s%~+luP8@88SDv$2~itqAmKv z=<P!e1>1L<FIpaRW1V+EP9W%|+9FXIspNf3;R1J$C_3zlsheh2n9=o->yAsh{&N9^ z(t8WtEsc(pu-bXOFJPJA_WOls-x-6L#`Pz{S(%pHnEU1HRGC=`TbS1Wnf308fWlh6 zpEKq?xWF)3^ao3A4QD%p=C<yAMrF76?Bt61C;Il0fWlp|xl4{)`b0H}u80e_`k!{` z_{%3se2hW)=5zNpIp@2rInjA{@00{qzLQ*E?u)#SEu2>NTd+Y`?EEE0zU4={VjfzQ zafT%XhAsHN?gz6;bbYBogYdPh^JYKKVqNw9@%OF;E?dscXL&Fwc1fP{{DLh^PirRE zFfgn;(6IVgMqX*Iub*3!sK)oZPp=l6&1Yd>kUeSH|DzYVbh>Z;TlR2m0)yVKlb(?c zQ?9i3SZD{tZ3#W~bmmIVQmG$r*Bx|PxLtgD;sI6X;9%pR$Q2=4=~tufs_c_jf3(J7 z=jGRHPSgu4oV~)IDSNa$QSBU;jEoi^e}A8U2d~FZ>3NsaKJP!zyyQm0Ql;|xEPD%6 z)1_s)@&dB*^72#L+S?!Bo~}|Xw_|!nc=2=zhIHQ3p*ycff0x~Bc;8>mj5FkcX#R!r z*RysXVX*KCUGOIQQgKJpdwr>DRy)6vjEy`Y(`PizVtcUZCznW`jc5GPUkcq7+69-x zOFp^vxj)T0t!K!P7rnvwrt6oon(rTuMKp%*yL;ug>cu`5hG%oiEy_=Bc3B^DR(aN= zRR>nbD^_iL`7ipaYFjcx`_^4cHfG3QTwW;CcPyxJww>y&?H}IRS8|qvC3mmb@mJ@f z!SRVN!xvci+U}nFxb=cK+ore67Q5)Le>l<Oi&nwe(=P5G|HPiye6)I>%CEz2a@@LA zta&xlU!1mm)z029XZLgAMg4VWmG6q4`t#T=nf2SW=KnSO-YPHh|M1VSfo*nw=jEe^ zr7PAnFYNl!ExPVt6zjLu`|=sBCgxh`{JUqk=fBv3)>P}Gor-gBT>hEZ{%W7%I>-G? ze}65$*ca|M?Y*VqzjGJop01E#h}!k@!TgSW^?wgC%Gu9<wSG}nKv=^5JDO#y_BXP} z|DX55pFRIsA;XKbm%siVPmP^hnRq<ZX63|JuiQdbgk^s{UVq`mDp~zG6YI-r{{LEP z!^z<E@^;mSDO!eBwxtQrb-z9iUUyLbO8VdOqffWLu`wu(@?8>qKIiS@lMD-1mY?1G zJO1~X^=rS`Rp<WSn|)!SltQKJ{~yBNFM>ui=GO~!vF~7*u{3YTf>Q}wSItvvlwvVh z0qHDVe*cu0!SP49W9r|t|CR3l6X#^;n7-@w$@Tl&;xbpU6>4xLI4r!Ty(O-3Q@WX6 zC)13u^$rXM{GuEQBn{t?H*7}Gip#4)WgNukegDrWu}Lv?yIXZ80|Nttr>mdKI;Vst E04;c6)Bpeg literal 0 HcmV?d00001 diff --git a/Exercise_2_5/Exercise_4.ipynb b/Exercise_2_5/Exercise_4.ipynb new file mode 100644 index 0000000..4ff8cb4 --- /dev/null +++ b/Exercise_2_5/Exercise_4.ipynb @@ -0,0 +1,362 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 4\n", + "This exercise cover topics of ICT and Grid Control Sysytems\n", + "For all calculation tasks this Notebook was prepared." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 2: Modulation\n", + "Modulation is the process of imprinting an information signal onto a carrier signal. In many cases the carrier signal is a sinusoidal, electromagnetic wave. When the frequency is fixed, amplitude and phase of the signal can be represented by a vector in the complex plane. Modulation schemes such as ASK or PSK use discrete values for these parameters to represent symbols. They can be visualized as points in this plane.\n", + "\n", + "<img src=\"ImagRep.png\" alt=\"Imaginary Representation of a signal\" width=\"300\" height=\"auto\">\n", + "<img src=\"ASKnPSK.png\" alt=\"ASK and PSK examples\" width=\"400\" height=\"auto\">\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Naturally, the closer these point are to each other, the easier it is to confuse them or for transmission errors to make one symbol look like the other. QAM tries to efficiently use the whole complex plane, while minimizing the possibility of confusion and the error rate.\n", + "For 16-QAM, it looks like this:\n", + "\n", + "\n", + "<img src=\"QAM_Amplitude.png\" alt=\"\" width=\"300\" height=\"auto\">\n", + "<img src=\"QAM_Phases.png\" alt=\"\" width=\"300\" height=\"auto\">\n", + "\n", + " Here, we need 3 Amplitudes and 12 phase angles to represent all symbols. The amplitudes ca be determined from the first given amplitude value `A1 = 1`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import math" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A1 = 1.\n", + "# Calculate missing values A2 and A3\n", + "\n", + "A2 = \n", + "A3 = \n", + "\n", + "print(f\"A1: {round(A1, 2)}\")\n", + "print(f\"A2: {round(A2, 2)}\")\n", + "print(f\"A3: {round(A3, 2)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Phases can be calculated using the amplitudes and some trigonometry. You may even use symmetry to you advantage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "phase = [[],[],[]] # Use phase[i][j] as the indices as indicated in the slides\n", + "\n", + "# You code goes here\n", + "\n", + "\n", + "for j in range(4):\n", + " for i in range(3):\n", + " print(f\"phi_{i+1},{j+1}: {round(math.degrees(phase[i][j]),2)}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 3: Multi-Dimensional Parity check\n", + "Multi-dimensional parity checks are a form of Forward-Error-Correction. A message in enlaced with parity bits such that in a matrix arangement and the parities can be checked per line and column. If a single bit is fliped, the corresponding line and column parity won't fit anymore and the error can be corrected." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "line_parity = False\n", + "column_parity = False\n", + "line_index = -1\n", + "column_index = -1\n", + "\n", + "block_line_size = 4\n", + "number = 0xDFC966\n", + "total_message_size = 24\n", + "#number = 0b1111111111001001011001101\n", + "#total_message_size = 25\n", + "\n", + "# Your code goes here\n", + "\n", + "# This should correct the error is the parity check works correctly:\n", + "if column_index != -1 and line_index != -1:\n", + " fault_shift = total_message_size-1 - column_index - line_index*(block_line_size+1)\n", + " corrected_number = number ^ 1<<fault_shift\n", + " print(f\"Corrected number: {hex(corrected_number)}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 4: Addressing and Routing\n", + "Dynamic routing protocols can build tables of valid routes to all connected networks by themselves. One such example is the Bellman-Ford-Algorithm. In this task we try to implement it in a distributed manner, as it would be in actual routers.\n", + "\n", + "It is you task to fill in the update table function of the Router-class below, such that the shourtest routes are determined dynamically for any scenario." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from typing import Self\n", + "\n", + "class Router:\n", + " def __init__(self, initial_table: pd.DataFrame) -> None:\n", + " self.neighbors = initial_table.copy()\n", + " self.neighbors = self.neighbors[self.neighbors[\"time\"] != 0]\n", + " self.routing_table = initial_table\n", + " self.name = self.routing_table[self.routing_table[\"time\"] == 0].index[0]\n", + "\n", + " def get_routing_table(self) -> pd.DataFrame:\n", + " return self.routing_table\n", + " \n", + " def update_routing_table(self, routers: dict[str, Self]):\n", + " for neighbor, dist in self.neighbors.iterrows():\n", + " # Your code goes here\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's try this from a fresh topology, where each router only knows their neighbor. Does it work? What can you observe in the outputs? Will this always look the same?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "r1 = Router(pd.DataFrame(data={\"time\": [0, 1, 4], \"via\": [\"A\", \"C\", \"D\"]}, index=[\"A\", \"C\", \"D\"]))\n", + "r2 = Router(pd.DataFrame(data={\"time\": [0, 2, 1], \"via\": [\"B\", \"C\", \"F\"]}, index=[\"B\", \"C\", \"F\"]))\n", + "r3 = Router(pd.DataFrame(data={\"time\": [1, 2, 0, 2], \"via\": [\"A\", \"B\", \"C\", \"D\"]}, index=[\"A\", \"B\", \"C\", \"D\"]))\n", + "r4 = Router(pd.DataFrame(data={\"time\": [4, 2, 0, 2, 1], \"via\": [\"A\", \"C\", \"D\", \"E\", \"F\"]}, index=[\"A\", \"C\", \"D\", \"E\", \"F\"]))\n", + "r5 = Router(pd.DataFrame(data={\"time\": [2, 0, 5], \"via\": [\"D\", \"E\", \"F\"]}, index=[\"D\", \"E\", \"F\"]))\n", + "r6 = Router(pd.DataFrame(data={\"time\": [1, 1, 5, 0], \"via\": [\"B\", \"D\", \"E\", \"F\"]}, index=[\"B\", \"D\", \"E\", \"F\"]))\n", + "\n", + "routers = {\"A\": r1, \"B\": r2, \"C\": r3, \"D\": r4, \"E\": r5, \"F\": r6}\n", + "\n", + "for _ in range(3):\n", + " table = pd.concat([r1.get_routing_table(),r2.get_routing_table(),r3.get_routing_table(),r4.get_routing_table(),r5.get_routing_table(),r6.get_routing_table()], axis=1).sort_index()\n", + " table.columns = pd.MultiIndex.from_tuples([(\"A\", \"time\"), (\"A\", \"via\"), (\"B\", \"time\"), (\"B\", \"via\"), (\"C\", \"time\"), (\"C\", \"via\"), (\"D\", \"time\"), (\"D\", \"via\"), (\"E\", \"time\"), (\"E\", \"via\"), (\"F\", \"time\"), (\"F\", \"via\")], names=[\"Router\", \"Parameters\"])\n", + " print(table)\n", + " for r in reversed(routers.values()):\n", + " r.update_routing_table(routers)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check what happens if a communication link is droped ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "r4.routing_table = r4.routing_table[r4.routing_table[\"via\"] != \"F\"] # We delete all routes D uses via F\n", + "r4.neighbors = r4.neighbors[r4.neighbors.index != \"F\"] # We delete F from Ds neighbor-table\n", + "r6.routing_table = r6.routing_table[r6.routing_table[\"via\"] != \"D\"] # We delete all routes F uses via D\n", + "r6.neighbors = r6.neighbors[r6.neighbors.index != \"D\"] # We delete D from F's neighbor-table\n", + "for _ in range(5):\n", + " table = pd.concat([r1.get_routing_table(),r2.get_routing_table(),r3.get_routing_table(),r4.get_routing_table(),r5.get_routing_table(),r6.get_routing_table()], axis=1).sort_index()\n", + " table.columns = pd.MultiIndex.from_tuples([(\"A\", \"time\"), (\"A\", \"via\"), (\"B\", \"time\"), (\"B\", \"via\"), (\"C\", \"time\"), (\"C\", \"via\"), (\"D\", \"time\"), (\"D\", \"via\"), (\"E\", \"time\"), (\"E\", \"via\"), (\"F\", \"time\"), (\"F\", \"via\")], names=[\"Router\", \"Parameters\"])\n", + " print(table)\n", + " for r in reversed(routers.values()):\n", + " r.update_routing_table(routers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 5: Network Performance Metrics\n", + "In a communication link there is several performance metrics which can be calculated, measured and evaluated. These metrics are for example latency, bandwidth, troughput, framerate, or the delay-bandwidth-product. These parameters can vary due to physical reasons, but also depending on the protocol layer, meassaging patter, etc." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dist_NY = 6000e3\n", + "dist_SF = 4000e3\n", + "c = 300e6\n", + "t_queue = 2e-3\n", + "t_proc = 5e-3\n", + "bw_NY = 10e6\n", + "bw_SF = 7e6\n", + "frame_size = 12e3\n", + "frame_per_min_NY = 10e3\n", + "frame_per_min_SF = 20e3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.a Latency" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "latency = \n", + "print(f\"Latency: {round(latency*1e3,2)} ms\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.b Actual Troughput" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "throughput_l1 = \n", + "print(f\"Layer 1 Throughut: {round(throughput_l1/1e6, 2)} MBit/s\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.c Layer 4 Troughput" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "headder_size = (42 + 20 + 20) * 8\n", + "throughput_l4 = \n", + "print(f\"Layer 4 Throughut: {round(throughput_l4/1e6, 2)} MBit/s\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.d Smaller Frames, but more of them" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "new_framerate = 100e3\n", + "throughput_l4_alt = \n", + "print(f\"Layer 4 Throughut: {round(throughput_l4_alt/1e3, 2)} kBit/s\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.e Round-Trip" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "throughput_l4_ack = \n", + "print(f\"Layer 4 Throughut: {round(throughput_l4_ack/1e3, 2)} kBit/s\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.f Delay-Bandwidth-Product" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "frames_to_buffer = \n", + "print(f\"The tranmitter needs to buffer {frames_to_buffer} frames for continuous transmission.\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Exercise_2_5/ImagRep.png b/Exercise_2_5/ImagRep.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5f2dba2f6ceb4e9060c1d9a3ba2c3feeda47f7 GIT binary patch literal 5871 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 a-|F9HzMjIBpzaLnuzI@sxvX<aXaWG-Oy}SL literal 0 HcmV?d00001 diff --git a/Exercise_2_5/QAM_Amplitude.png b/Exercise_2_5/QAM_Amplitude.png new file mode 100644 index 0000000000000000000000000000000000000000..0ae31a7fbade25b6479715a36c03a4dd142b4449 GIT binary patch literal 16144 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 a`2XwjBHP@}u^T{}vprq?T-G@yGywo?A+F2- literal 0 HcmV?d00001 diff --git a/Exercise_2_5/QAM_Phases.png b/Exercise_2_5/QAM_Phases.png new file mode 100644 index 0000000000000000000000000000000000000000..9bbeb9389b76cfa42b38f77657d133dbbc69c639 GIT binary patch literal 20935 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 T!@brMG|lbl>gTe~DWM4f`2b{x literal 0 HcmV?d00001 -- GitLab From 7f14f00a4b6553c0e8c8eda2478c0c08935432c7 Mon Sep 17 00:00:00 2001 From: Markus <m.stroot@iaew.rwth-aachen.de> Date: Tue, 2 Jul 2024 12:36:27 +0200 Subject: [PATCH 14/23] Updates to Cryptography notebook --- .gitignore | 3 + Excercise_3/Cryptography.ipynb | 145 ++++++++++++++++++++++++++++++++- Exercise_2_5/Exercise_4.ipynb | 18 ++-- 3 files changed, 158 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index c2d867e..369caa5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ __pycache__/ # pycharm .idea +Excercise_3/Cryptography-Solutions.ipynb +Exercise_2_5/Exercise_4 _solution.ipynb +*.zip diff --git a/Excercise_3/Cryptography.ipynb b/Excercise_3/Cryptography.ipynb index 96b9a4a..4a40c6b 100644 --- a/Excercise_3/Cryptography.ipynb +++ b/Excercise_3/Cryptography.ipynb @@ -34,7 +34,7 @@ "id": "ed7799e9", "metadata": {}, "source": [ - "## Implementation of the Cypher\n", + "## Implementation of the Caesar Cypher\n", "\n", "Let's begin by encoding the message. As described above we aim at a simple shift cypher, which shifts every letter in the message a certain number of letters down the alphabet, looping back to the beginning after the end. For instance, when we apply a shift of 2, the letter 'a' becomes 'c', 'b' becomes 'd', etc. As a result, the word \"at\" transforms into \"cv\". This applies to lower-case letters as well as upper-case. We will ignore special characters like punctuation or white spaces for now." ] @@ -307,6 +307,147 @@ "- Advantage: Finds key without having to try all possible ones; Disadvantage: Needs a somewhat large amount of data for statistical properties to emerge, as well as knowledge about the underlying statistics.\n", "- In order to make statistical properties disapear, we need to introduce randomness into the cypher. The symbol frequencies of the cypher text should not depend on the original message." ] + }, + { + "cell_type": "markdown", + "id": "a34f3806", + "metadata": {}, + "source": [ + "## Diffie-Hellman key exchange\n", + "If we want to use symmetric encryption, both communication partners need to use the same key. If we simply transmit the key, everyone listening can use them. We need a secure way to exchange symmetric keys over an insecure network. The Diffie-Hellman algorithm provides a way of generating symetric keys by exchanging public info, without outsiders being able to reconstruct the key.\n", + "\n", + "It works as follows:\n", + "1. A public pair of numbers is used/shared, anyone can know them (g, p; g < p) \n", + "2. Each participant chooses a private key (Alice uses key “a” and Bob key “b”)\n", + "3. Both calculate $s_a = g^a \\, mod\\, p$ and $s_b = g^b \\, mod\\, p$\n", + "4. They exchange the results\n", + "5. Each one then calculates the key as: $k=s_b^a\\, mod\\, p = s_a^b\\, mod\\, p$\n", + "\n", + "Please implement an example below to check if it works" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4deae21e", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "g = random.randint(10,50)\n", + "p =\n", + "\n", + "a =\n", + "b =\n", + "\n", + "s_a =\n", + "s_b =\n", + "\n", + "k_a =\n", + "k_b =\n", + "\n", + "print(f\"Public info: g = {g}; p = {p}\")\n", + "print(f\"Secret Key of Alice: {a}. Public key of Alice: {s_a}. Shared secret as calculated by Alice: {k_a}\")\n", + "print(f\"Secret Key of Bob: {b}. Public key of Bob: {s_b}. Shared secret as calculated by Bob: {k_b}\")\n", + "print(f\"Did the procedure work: {k_a == k_b}\")" + ] + }, + { + "cell_type": "markdown", + "id": "9889ea2c", + "metadata": {}, + "source": [ + "## RSA\n", + "The RSA cryptosystem is an asymetric system. Therefore it supports creating two different keys, where one key is the inverse of the other. This supports public-key encryption, so everyone can encrypt messages using the public key that only the intended receriver can read using the private one. Reversely, an entity can generate a message using its private key, which everyone can confirm is generated by that entity using its public key.\n", + "\n", + "To generate the keys several steps are necessary:\n", + "1. Generate two random prime numbers p and q\n", + "2. Calculate $n=pq$; This is the systems modulo\n", + "3. Calculate $\\phi(n)=(p-1)(q-1)$\n", + "4. Choose encryption key e such that it is coprime with $\\phi(n)$ (gcd = 1)\n", + "5. Generate decryption key d such that $de = 1 \\quad mod\\, \\phi(n)$\n", + "\n", + "Our public key is now the combination of e and n\n", + "\n", + "Encryption of a message m is now done like this:\n", + "- $m_e = m^e \\quad mod \\, n$\n", + "\n", + "And using decryption d should give back m:\n", + "- $m = m_e^d \\quad mod \\, n$\n", + "\n", + "While using e again should generally not work:\n", + "- $m \\neq m_e^e \\quad mod \\, n$\n", + "\n", + "Please implement and try out for yourself below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2cb73e37", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "import math\n", + "\n", + "def check_prime(number):\n", + " # Put code for checking if a number is prinme here\n", + " \n", + " \n", + "def check_coprime(a, b):\n", + " # Put code to check if two numbers are coprime here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad60e2dd", + "metadata": {}, + "outputs": [], + "source": [ + "primes = []\n", + "\n", + "# Put code generating two random primes here\n", + "\n", + "p = primes[0]\n", + "q = primes[1]\n", + "\n", + "# Calculate the necessary numbers and keys\n", + "n = \n", + "phi_n = \n", + "\n", + "e=\n", + "d=\n", + "\n", + "print(f\"Primes chosen: ({p}, {q})\")\n", + "print(f\"n: {n}\")\n", + "print(f\"Phi_n: {phi_n}\")\n", + "print(f\"encryption: {e}\")\n", + "print(f\"decryption: {d}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b310b0ee", + "metadata": {}, + "outputs": [], + "source": [ + "# you can coose any message here\n", + "message = 721\n", + "\n", + "# Calculate the encryptet message, the wrong decryption using the same key and the correct decryption using the private key\n", + "message_encrypt = \n", + "message_decrypt_wrong = \n", + "message_decrypt = \n", + "\n", + "print(f\"Message: {message}\")\n", + "print(f\"Encrypted message: {message_encrypt}\")\n", + "print(f\"Wrongly decrypted message: {message_decrypt_wrong}\")\n", + "print(f\"Right decrypted message: {message_decrypt}\")" + ] } ], "metadata": { @@ -325,7 +466,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/Exercise_2_5/Exercise_4.ipynb b/Exercise_2_5/Exercise_4.ipynb index 4ff8cb4..41b2a63 100644 --- a/Exercise_2_5/Exercise_4.ipynb +++ b/Exercise_2_5/Exercise_4.ipynb @@ -237,7 +237,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 5.a Latency" + "### a) Latency\n", + "What is the one-way latency of this communication link?" ] }, { @@ -254,7 +255,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 5.b Actual Troughput" + "### b) Layer 1 troughput\n", + "What is the max. throughput of raw bits, the Layer 1 throughput?" ] }, { @@ -271,7 +273,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 5.c Layer 4 Troughput" + "### c) Layer 4 troughput\n", + "How much layer 4 data throughput can we expect?" ] }, { @@ -289,7 +292,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 5.d Smaller Frames, but more of them" + "### d) Smaller Frames, but more of them\n", + "How much layer 4 data throughput do we get under the same conditions but with a frame size of 1200 bit? Assume the link is able to handle 10x the amount of frames to keep a similar layer 1 throughput!\n" ] }, { @@ -307,7 +311,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 5.e Round-Trip" + "### e) Round-Trip\n", + "Assume conditions of subtask c). Now the top layer protocol requires acknowledgements from the receiving station after each packet before continuing to send data. What is the layer 4 throughput now? For acknowledgement, only transmission time can be neglected." ] }, { @@ -324,7 +329,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 5.f Delay-Bandwidth-Product" + "### f) Delay-Bandwidth-Product\n", + "In Full-Duplex communication, a more efficient scheme would be to acknowledge only every few packets. How many max. size packets would the transmitter need to buffer to be able to continuously send data? (round up)" ] }, { -- GitLab From b940d41783090169e4bc4940af21076b4d872e37 Mon Sep 17 00:00:00 2001 From: "f.tischbein" <f.tischbein@iaew.rwth-aachen.de> Date: Thu, 18 Jul 2024 12:46:53 +0200 Subject: [PATCH 15/23] Add Solution for Asset Management --- Exercise_4/2024_07_18_A6_v1.ipynb | 627 ++++++++++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 Exercise_4/2024_07_18_A6_v1.ipynb diff --git a/Exercise_4/2024_07_18_A6_v1.ipynb b/Exercise_4/2024_07_18_A6_v1.ipynb new file mode 100644 index 0000000..3e18187 --- /dev/null +++ b/Exercise_4/2024_07_18_A6_v1.ipynb @@ -0,0 +1,627 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# DEV Exercise 6\n", + "In this Jupyter notebook we will deal with the calculation of investment and operational costs. If you have not yet installed the packages required for this exercise, run the following cell to install them." + ], + "metadata": { + "collapsed": false + }, + "id": "72ab3cf5505dbbc2" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "!pip install pandas\n", + "!pip install pandapower\n", + "!pip install simbench" + ], + "metadata": { + "collapsed": false + }, + "id": "e99cc0f65671eb71" + }, + { + "cell_type": "markdown", + "source": [ + "Now run the following cell to import the most important libraries. You can run a cell either by clicking Run on the toolbar or by pressing CTRL+RETURN." + ], + "metadata": { + "collapsed": false + }, + "id": "ddeb3acb51e3e4cd" + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-06-03T14:20:24.081312800Z", + "start_time": "2024-06-03T14:20:24.064701400Z" + } + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.simplefilter(action='ignore', category=FutureWarning)\n", + "\n", + "import pandas as pd\n", + "pd.options.display.max_rows = 10\n", + "\n", + "import pandapower as pp\n", + "import simbench as sb" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Example grid\n", + "\n", + "We will carry out the calculation using a [SimBench](https://simbench.readthedocs.io/en/stable/) example grid. SimBench is a database with synthetic grid data that maps different grid structures in low voltage. Import the grid “1-LV-rural1--0-sw” and print its properties (number and type of assets). The standard types in particular are required later for the calculation of annuities. \n" + ], + "metadata": { + "collapsed": false + }, + "id": "4963cb76c621b1bc" + }, + { + "cell_type": "code", + "execution_count": 6, + "outputs": [ + { + "data": { + "text/plain": " name std_type from_bus to_bus length_km \\\n0 LV1.101 Line 1 NAYY 4x150SE 0.6/1kV 9 2 0.055767 \n1 LV1.101 Line 2 NAYY 4x150SE 0.6/1kV 13 11 0.053576 \n2 LV1.101 Line 3 NAYY 4x150SE 0.6/1kV 6 3 0.049814 \n3 LV1.101 Line 4 NAYY 4x150SE 0.6/1kV 8 1 0.017886 \n4 LV1.101 Line 5 NAYY 4x150SE 0.6/1kV 7 10 0.016089 \n.. ... ... ... ... ... \n8 LV1.101 Line 9 NAYY 4x150SE 0.6/1kV 5 13 0.137215 \n9 LV1.101 Line 10 NAYY 4x150SE 0.6/1kV 3 0 0.132499 \n10 LV1.101 Line 12 NAYY 4x150SE 0.6/1kV 1 3 0.016207 \n11 LV1.101 Line 13 NAYY 4x150SE 0.6/1kV 12 8 0.046015 \n12 LV1.101 Line 11 NAYY 4x150SE 0.6/1kV 4 5 0.002583 \n\n r_ohm_per_km x_ohm_per_km c_nf_per_km g_us_per_km max_i_ka df \\\n0 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n1 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n2 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n3 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n4 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n.. ... ... ... ... ... ... \n8 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n9 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n10 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n11 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n12 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n\n parallel type in_service voltLvl max_loading_percent subnet \n0 1 cs True 7 100.0 LV1.101 \n1 1 cs True 7 100.0 LV1.101 \n2 1 cs True 7 100.0 LV1.101 \n3 1 cs True 7 100.0 LV1.101 \n4 1 cs True 7 100.0 LV1.101 \n.. ... ... ... ... ... ... \n8 1 cs True 7 100.0 LV1.101 \n9 1 cs True 7 100.0 LV1.101 \n10 1 cs True 7 100.0 LV1.101 \n11 1 cs True 7 100.0 LV1.101 \n12 1 cs True 7 100.0 LV1.101 \n\n[13 rows x 17 columns]", + "text/html": "<div>\n<style scoped>\n .dataframe tbody tr th:only-of-type {\n vertical-align: middle;\n }\n\n .dataframe tbody tr th {\n vertical-align: top;\n }\n\n .dataframe thead th {\n text-align: right;\n }\n</style>\n<table border=\"1\" class=\"dataframe\">\n <thead>\n <tr style=\"text-align: right;\">\n <th></th>\n <th>name</th>\n <th>std_type</th>\n <th>from_bus</th>\n <th>to_bus</th>\n <th>length_km</th>\n <th>r_ohm_per_km</th>\n <th>x_ohm_per_km</th>\n <th>c_nf_per_km</th>\n <th>g_us_per_km</th>\n <th>max_i_ka</th>\n <th>df</th>\n <th>parallel</th>\n <th>type</th>\n <th>in_service</th>\n <th>voltLvl</th>\n <th>max_loading_percent</th>\n <th>subnet</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>LV1.101 Line 1</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>9</td>\n <td>2</td>\n <td>0.055767</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>1</th>\n <td>LV1.101 Line 2</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>13</td>\n <td>11</td>\n <td>0.053576</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>2</th>\n <td>LV1.101 Line 3</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>6</td>\n <td>3</td>\n <td>0.049814</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>3</th>\n <td>LV1.101 Line 4</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>8</td>\n <td>1</td>\n <td>0.017886</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>4</th>\n <td>LV1.101 Line 5</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>7</td>\n <td>10</td>\n <td>0.016089</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>...</th>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n </tr>\n <tr>\n <th>8</th>\n <td>LV1.101 Line 9</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>5</td>\n <td>13</td>\n <td>0.137215</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>9</th>\n <td>LV1.101 Line 10</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>3</td>\n <td>0</td>\n <td>0.132499</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>10</th>\n <td>LV1.101 Line 12</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>1</td>\n <td>3</td>\n <td>0.016207</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>11</th>\n <td>LV1.101 Line 13</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>12</td>\n <td>8</td>\n <td>0.046015</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>12</th>\n <td>LV1.101 Line 11</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>4</td>\n <td>5</td>\n <td>0.002583</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n </tbody>\n</table>\n<p>13 rows × 17 columns</p>\n</div>" + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sb_code1 = \"1-LV-rural1--0-sw\"\n", + "net = sb.get_simbench_net(sb_code1)\n", + "net\n", + "net.line" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:21:02.405316800Z", + "start_time": "2024-06-03T14:20:58.805268800Z" + } + }, + "id": "ce2565ab7f9d932b" + }, + { + "cell_type": "markdown", + "source": [ + "Afterwards, you can plot the SimBench grid by using [the pandapower simple plotting tool](https://pandapower.readthedocs.io/en/v2.0.1/plotting/matplotlib/simple_plot.html)." + ], + "metadata": { + "collapsed": false + }, + "id": "f25c7b3b43552621" + }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [ + { + "data": { + "text/plain": "<Figure size 1000x800 with 1 Axes>", + "image/png": "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AMA0eAYdACrii1/8Yt70pjclSQ477LC89a1vzVVXXZVHHnkkc+fOzWGHHZZTTz019957b4499tisWLEiIyMjufvuu7Pzzjv39/AAwJQEOgBUxHOe85xcf/31SZJtt902S5cufdJjRkZG8trXvjYLFizIpz71qSTJ3/7t3+b9739/T88KAEyfQAeACli5cuW0Bt/22WefNcvuJ5xwQr73ve9162gAwAzxGnQAqIBly5Y96cde85rX5LLLLstvfvOb3HLLLXnf+96XbbfdNknWxHmSSZ9pBwDK4xl0AKiA+++/PwsXLlzz9le/+tW88pWvfNLjfvnLX+Z5z3te7rnnnjU/9oIXvCCXXXZZT84JAGw+z6ADQAX8y7/8y3pv77fffpM+7mlPe9qa155POOqoo7p1LABgBgl0AKiAb37zm+u9/Z73vCerVq2a9LEHHHBAGo3Gmrff+MY3dvVsAMDMEOgAUAEPPvjgem9ffvnleeELX5irrroqE69We/zxx3PBBRfkuOOOy7qvYJt4XToAULbhfh8AAJjanDlz1vv+448/nquvvjrPe97zsvvuu2ennXbKnXfeOemY3LrvCwCUyzPoAFABBx100Jrvv+Md78iuu+665u277747//Ef/zFpnO++++6ZP39+T84IAGwZgQ4AFXDGGWes+f43vvGN3HTTTfnyl7+c4447LvPmzUuz2cwOO+yQ173udTnppJPWe791X48OAJRLoANABRx66KF57nOfm6T9pdROOumkHHDAAfnBD36QRx99NGNjY1m8eHHmzZuXb3/720mS2bNn5/TTT+/nsQGAafB10AGgIu68884cddRRefjhh9f82M4775xDDz00IyMj+e53v5vVq1ev+bkLLrjAgjsAVIhAB4AKWbRoUU466aTcfffdG33MyMhIzj777Jx66qk9PBkAsKVccQeACjnooIOyePHifPazn83w8PpfjGX77bfPX/zFX+SOO+4Q5wBQQZ5BB4AKWrp0aRYsWJAkedaznpWvfe1r2X333TMyMtLfgwEAm83XQQeACrrtttvWfP/www/P0572tD6eBgCYCa64A0AFLV68eM33DzzwwD6eBACYKQIdACpo3UA/4IAD+ngSAGCmCHQAqKBbb711zfc9gw4A9SDQAaCCJp5B32677bLLLrv0+TQAwEwQ6ABQMUuXLs0999yTpH29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" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": "<Axes: >" + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pp.plotting.simple_plot(net, show_plot=True)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:20:39.998814Z", + "start_time": "2024-06-03T14:20:39.471146800Z" + } + }, + "id": "2eb6d9517e99be23" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2a \n", + "\n", + "To calculate the annuities, we must first determine the investment costs of the lines and transformer types. For this purpose, read these from the Excel table using [the pandas function \"read_excel\"](https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html)." + ], + "metadata": { + "collapsed": false + }, + "id": "e43234c36ca7e4ba" + }, + { + "cell_type": "code", + "execution_count": 8, + "outputs": [], + "source": [ + "line_std_types = pd.read_excel(io=\"./std_type_costs.xlsx\", index_col=[0], sheet_name=\"line_std_types\")\n", + "trafo_std_types = pd.read_excel(io=\"./std_type_costs.xlsx\", index_col=[0], sheet_name=\"trafo_std_types\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:21:58.923764700Z", + "start_time": "2024-06-03T14:21:58.809907500Z" + } + }, + "id": "c6f5410eee07a074" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2b\n", + "Calculate the total investment cost in t=0 for the transformer and the lines.\n", + "For the equipment with unit prices the total costs can be calculated via\n", + "$C_{inv} = \\sum_{pc=1}^{n} {C_{pc}} = n \\cdot C_{pc}$" + ], + "metadata": { + "collapsed": false + }, + "id": "90aeb0e3ed2ee0d4" + }, + { + "cell_type": "code", + "execution_count": 9, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The investment costs for trafos are : 13.0 mio. €\n" + ] + } + ], + "source": [ + "trafo_name = net.trafo.std_type[0]\n", + "c_inv_trafo = len(net.trafo) * trafo_std_types.at[trafo_name, \"cost_per_piece\"]\n", + "print(f\"The investment costs for trafos are : {round(c_inv_trafo/1e6, 2)} mio. €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:02.934409600Z", + "start_time": "2024-06-03T14:22:02.914839400Z" + } + }, + "id": "527eba7f1fdd1827" + }, + { + "cell_type": "markdown", + "source": [ + "For the equipment with length related costs:\n", + "$C_{inv} = \\sum_{pc=1}^{n} {l_{pc} \\cdot C_l} = (\\sum_{pc=1}^{n} {l_{pc}}) \\cdot C_l$.\n", + "First sum up over the total line length using [pandas groupby](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html)." + ], + "metadata": { + "collapsed": false + }, + "id": "de5e30b6e28016b7" + }, + { + "cell_type": "code", + "execution_count": 10, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The line length is : 0.56 km\n" + ] + } + ], + "source": [ + "line_name = net.line.std_type[0]\n", + "sum_lines = net.line[[\"std_type\", \"length_km\"]].groupby(\"std_type\").sum().at[line_name, \"length_km\"]\n", + "print(f\"The line length is : {round(sum_lines, 3)} km\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:07.921782200Z", + "start_time": "2024-06-03T14:22:07.887759400Z" + } + }, + "id": "4731e97d3b9e66f1" + }, + { + "cell_type": "code", + "execution_count": 11, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The investment costs for lines are : 0.01 mio. €\n" + ] + } + ], + "source": [ + "c_inv_lines = sum_lines * line_std_types.at[line_name, \"cost_per_km\"]\n", + "print(f\"The investment costs for lines are : {round(c_inv_lines/1e6, 2)} mio. €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:09.292713800Z", + "start_time": "2024-06-03T14:22:09.267721Z" + } + }, + "id": "3e4b323df9b033ec" + }, + { + "cell_type": "markdown", + "source": [ + "Afterwards, calculate the total investment cost of the grid by:\n", + "$C_{grid,inv} = \\sum_{equip.} {C_{inv,equip.}}$" + ], + "metadata": { + "collapsed": false + }, + "id": "1262245f8ee4319d" + }, + { + "cell_type": "code", + "execution_count": 12, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The total grid costs are : 13.01 mio. €\n" + ] + } + ], + "source": [ + "c_total = c_inv_trafo + c_inv_lines\n", + "print(f\"The total grid costs are : {round(c_total/1e6, 2)} mio. €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:17.122947500Z", + "start_time": "2024-06-03T14:22:17.097954900Z" + } + }, + "id": "f56701e0558fd50e" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2c\n", + "Calculate the annuity factors for the different lifetimes and components.\n", + "The annuity factors for the different lifetimes can be calculated via:\n", + "$a=\\frac{q^{T,max} \\cdot (q-1)}{q^{T,max}-1}$\n", + "\n", + "The lifetimes $T_{max}$ of the assets can be found in the Excel tables or data frames. First, define a function to calculate the annuity. This should have the lifetime and the discount rate $q = 1+r$ as input data. Usually, distribution grid operators assume an interest rate of $r=5\\%$." + ], + "metadata": { + "collapsed": false + }, + "id": "4a8f16d1e3d93bcc" + }, + { + "cell_type": "code", + "execution_count": 13, + "outputs": [], + "source": [ + "interestrate=0.05\n", + "\n", + "def annuity(n, r=interestrate):\n", + " \"\"\"Calculate the annuity factor for an asset with lifetime n years and\n", + " discount rate of r\"\"\"\n", + "\n", + " q=1+r\n", + "\n", + " if r > 0:\n", + " return (q**n*(q-1))/(q**n-1)\n", + " else:\n", + " return 1/n" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:21.141660Z", + "start_time": "2024-06-03T14:22:21.122542800Z" + } + }, + "id": "ba8c3aebb2b2edf1" + }, + { + "cell_type": "markdown", + "source": [ + "The following annuity costs then result for the components:" + ], + "metadata": { + "collapsed": false + }, + "id": "8bc1eeef24887502" + }, + { + "cell_type": "code", + "execution_count": 14, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The annuity factor for the lines is : 0.0611\n" + ] + } + ], + "source": [ + "ann_lines = annuity(line_std_types.at[line_name, \"lifetime\"])\n", + "print(f\"The annuity factor for the lines is : {round(ann_lines, 4)}\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:23.374625200Z", + "start_time": "2024-06-03T14:22:23.328846900Z" + } + }, + "id": "e63a003d70957a59" + }, + { + "cell_type": "code", + "execution_count": 15, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The annuity factor for the trafos is : 0.0651\n" + ] + } + ], + "source": [ + "ann_trafo = annuity(trafo_std_types.at[trafo_name, \"lifetime\"])\n", + "print(f\"The annuity factor for the trafos is : {round(ann_trafo, 4)}\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:24.896539Z", + "start_time": "2024-06-03T14:22:24.868448200Z" + } + }, + "id": "966f8b18dc754e17" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2d\n", + "Afterwards, calculate the operating costs for the transformer and the lines. The operating costs can be found in the corresponding Excel files or data frames. The operating costs correspond to the multiplication of the investment costs with the specific operating costs from the Excel table or data frame." + ], + "metadata": { + "collapsed": false + }, + "id": "6e9b5e1600f9bf78" + }, + { + "cell_type": "code", + "execution_count": 16, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The operating costs for lines are : 156.49 €\n" + ] + } + ], + "source": [ + "c_o_lines = c_inv_lines * line_std_types.at[line_name, \"operating_cost\"]\n", + "print(f\"The operating costs for lines are : {round(c_o_lines, 2)} €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:36.659044600Z", + "start_time": "2024-06-03T14:22:36.638976800Z" + } + }, + "id": "644d4a2306910ee6" + }, + { + "cell_type": "code", + "execution_count": 17, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The operating costs for transformer are : 0.39 mio. €\n" + ] + } + ], + "source": [ + "c_o_trafo = c_inv_trafo * trafo_std_types.at[trafo_name, \"operating_cost\"]\n", + "print(f\"The operating costs for transformer are : {round(c_o_trafo/1e6, 2)} mio. €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:39.725035900Z", + "start_time": "2024-06-03T14:22:39.704038Z" + } + }, + "id": "1faf1a9504e028da" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2e\n", + "Calculate the annual cost of the grid equipment (sum of operating and investment costs)." + ], + "metadata": { + "collapsed": false + }, + "id": "79769693879cb833" + }, + { + "cell_type": "code", + "execution_count": 18, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The annual grid costs are : 1.24 mio. €\n" + ] + } + ], + "source": [ + "c_ann_total = ann_lines * c_inv_lines + ann_trafo * c_inv_trafo + c_o_lines + c_o_trafo \n", + "print(f\"The annual grid costs are : {round(c_ann_total/1e6, 2)} mio. €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:45.654863600Z", + "start_time": "2024-06-03T14:22:45.633570100Z" + } + }, + "id": "de48aec2ff9058bf" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2f\n", + "In the course of digitizing the distribution grids, it is advisable to equip most of the LV system equipment with measurement technology. For our system, the following assumptions can be made:\n", + "- The specific investment costs for the measurement technology system in the transformer station is 500.000€, the interest rate equals 5%/a and its lifetime equals 20 years\n", + "- Every grid customer within our grid will also be equipped with a smart meter. As the smart meters belong to the metering point operator and not the distribution grid operator, there are no investment costs here.\n", + "- Because metering technology allows the grid to operate more efficiently, the lifetimes of all other technologies increase by 5 years\n", + "\n", + "Calculate the new annuity of investment costs for the total system with the measurement technology" + ], + "metadata": { + "collapsed": false + }, + "id": "ee9bcd85e1c42abc" + }, + { + "cell_type": "code", + "execution_count": 19, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The new annual grid costs are : 1.22 mio. €\n" + ] + } + ], + "source": [ + "c_ann_trafo = 1 * trafo_std_types.at[trafo_name, \"cost_per_piece\"] * annuity(trafo_std_types.at[trafo_name, \"lifetime\"] + 5)\n", + "c_ann_lines = sum_lines * line_std_types.at[line_name, \"cost_per_km\"] * annuity(line_std_types.at[line_name, \"lifetime\"] + 5)\n", + "\n", + "c_inv_measure = 500000\n", + "lifetime_measure = 20\n", + "c_ann_measure = annuity(lifetime_measure) * c_inv_measure\n", + "\n", + "c_ann_total_new = c_ann_trafo + c_ann_lines + c_o_trafo + c_o_lines + c_ann_measure\n", + "print(f\"The new annual grid costs are : {round(c_ann_total_new/1e6, 2)} mio. €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:48.991815900Z", + "start_time": "2024-06-03T14:22:48.974735500Z" + } + }, + "id": "e9bf09de56cfedb1" + }, + { + "cell_type": "markdown", + "source": [ + "### Task 2g\n", + "What are the maximum annual operating costs for the measurement equipment in order to still be cheaper than without measurement equipment?" + ], + "metadata": { + "collapsed": false + }, + "id": "51cf92fb26790ff" + }, + { + "cell_type": "code", + "execution_count": 20, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The maximum annual operating costs can be : 11651.6 €\n" + ] + } + ], + "source": [ + "c_o_measure = c_ann_total - c_ann_total_new\n", + "print(f\"The maximum annual operating costs can be : {round(c_o_measure, 2)} €\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-03T14:22:54.454657700Z", + "start_time": "2024-06-03T14:22:54.436729800Z" + } + }, + "id": "b749b6d14d16ff43" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "dfd9b25d20fc7b6c" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} -- GitLab From f828c0bad6bd4598686e9343b91c04de95f34131 Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:41:09 +0200 Subject: [PATCH 16/23] change file name --- ...{2024_02_23_DEV_UE2_A2_v2.ipynb => Exercise_2_DEV_A2_v2.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Excercise_2/{2024_02_23_DEV_UE2_A2_v2.ipynb => Exercise_2_DEV_A2_v2.ipynb} (100%) diff --git a/Excercise_2/2024_02_23_DEV_UE2_A2_v2.ipynb b/Excercise_2/Exercise_2_DEV_A2_v2.ipynb similarity index 100% rename from Excercise_2/2024_02_23_DEV_UE2_A2_v2.ipynb rename to Excercise_2/Exercise_2_DEV_A2_v2.ipynb -- GitLab From 709f327257a1995b05b81294053cca5e534c6d71 Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:42:14 +0200 Subject: [PATCH 17/23] Edit name --- ..._v2_students.ipynb => Exercise_2_DEV_UE2_A2_v2_students.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Excercise_2/{2024_02_23_DEV_UE2_A2_v2_students.ipynb => Exercise_2_DEV_UE2_A2_v2_students.ipynb} (100%) diff --git a/Excercise_2/2024_02_23_DEV_UE2_A2_v2_students.ipynb b/Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb similarity index 100% rename from Excercise_2/2024_02_23_DEV_UE2_A2_v2_students.ipynb rename to Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb -- GitLab From 6216086b1cf4f867acce069ab4c0e55e3dea8079 Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:43:16 +0200 Subject: [PATCH 18/23] Edit .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 369caa5..7e83bf6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ __pycache__/ .idea Excercise_3/Cryptography-Solutions.ipynb Exercise_2_5/Exercise_4 _solution.ipynb +Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb *.zip -- GitLab From 9f81b80a78f16b3e4593d536ff1a690861f137c7 Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:44:09 +0200 Subject: [PATCH 19/23] Edit name 2024_06_03_A6_v1_students.ipynb --- ...06_03_A6_v1_students.ipynb => exercise_4_A6_v1_students.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Exercise_4/{2024_06_03_A6_v1_students.ipynb => exercise_4_A6_v1_students.ipynb} (100%) diff --git a/Exercise_4/2024_06_03_A6_v1_students.ipynb b/Exercise_4/exercise_4_A6_v1_students.ipynb similarity index 100% rename from Exercise_4/2024_06_03_A6_v1_students.ipynb rename to Exercise_4/exercise_4_A6_v1_students.ipynb -- GitLab From 91f220632ab79b9528fd7b25b69a8d7e4665c076 Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:44:56 +0200 Subject: [PATCH 20/23] Edit 2024_07_18_A6_v1.ipynb --- Exercise_4/{2024_07_18_A6_v1.ipynb => exercise_4_A6_v1.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Exercise_4/{2024_07_18_A6_v1.ipynb => exercise_4_A6_v1.ipynb} (100%) diff --git a/Exercise_4/2024_07_18_A6_v1.ipynb b/Exercise_4/exercise_4_A6_v1.ipynb similarity index 100% rename from Exercise_4/2024_07_18_A6_v1.ipynb rename to Exercise_4/exercise_4_A6_v1.ipynb -- GitLab From e645906b8cfccb142e91bb9589053249857a82ad Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:45:33 +0200 Subject: [PATCH 21/23] Edit .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7e83bf6..f5cbd29 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ __pycache__/ Excercise_3/Cryptography-Solutions.ipynb Exercise_2_5/Exercise_4 _solution.ipynb Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb +Exercise_4/exercise_4_A6_v1_students.ipynb *.zip -- GitLab From 504fc3ee161d54f736900382483f5a3101fede46 Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:50:00 +0200 Subject: [PATCH 22/23] Delete Exercise_2_DEV_UE2_A2_v2_students.ipynb --- .../Exercise_2_DEV_UE2_A2_v2_students.ipynb | 521 ------------------ 1 file changed, 521 deletions(-) delete mode 100644 Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb diff --git a/Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb b/Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb deleted file mode 100644 index c489a49..0000000 --- a/Excercise_2/Exercise_2_DEV_UE2_A2_v2_students.ipynb +++ /dev/null @@ -1,521 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "source": [ - "# DEV Exercise 2" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "This Jupyter notebook contains tasks that are calculated for you on the blackboard during the exercise session. To practice using python and to see the advantage of programming when dealing with data, you will reprogram parts of it in this Jupyter notebook. If you have not yet installed the packages required for this exercise, run the following cell to install them." - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "!pip install pandas\n", - "!pip install numpy\n", - "!pip install scipy\n", - "!pip install openpyxl" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "markdown", - "source": [ - "Now run the following cell to import the most important libraries. You can run a cell either by clicking `Run` on the toolbar or by pressing `CTRL+RETURN`." - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "name": "#%%\n" - }, - "ExecuteTime": { - "end_time": "2024-02-23T12:58:40.909857800Z", - "start_time": "2024-02-23T12:58:28.941463400Z" - } - }, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import pandas as pd\n", - "import numpy as np\n", - "from scipy.optimize import curve_fit" - ] - }, - { - "cell_type": "markdown", - "source": [ - "### Predefine functions\n", - "It is good programming practice to define functions at the beginning that you want to use again and again in the course of the code. You can find instructions with examples for defining functions under the following [link](https://www.w3schools.com/python/python_functions.asp). For reasons of overview, however, we will always define these in the respective task section first. As an example, we give you the function <code> round_up(x, decimals) </code>. This function always rounds up values and will be used more frequently throughout the code." - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "def round_up(x, decimals: int):\n", - " \"\"\"\n", - " Returns the numerical value given in \"value\", rounded up to the given number of decimal places given in \"decimals\". This function is particularly relevant when dealing with measurement uncertainties, as these must always be rounded up.\n", - "\n", - " :param x: value to be rounded\n", - " :param decimals: number of decimals\n", - " :return: rounded up value\n", - " \"\"\"\n", - " value = np.ceil(pow(10, decimals)*x) / pow(10, decimals)\n", - "\n", - " return value" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2a\n", - "First, the measurement data must be read in from the Excel spreadsheet. The table contains the measured voltages and currents, each with their uncertainties. Use the [pd.read_excel](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html) function to do this.\n" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": 3, - "outputs": [], - "source": [ - "### First, the data needs to be loaded from the given xlsx-file. Note that all datatypes shall be set to float.\n", - "\n", - "data = \n", - "\n", - "### Define arrays with the corresponding voltage and current values for later use.\n", - "U = \n", - "sig_U = \n", - "I = \n", - "sig_I = " - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-02-23T13:00:28.694732900Z", - "start_time": "2024-02-23T13:00:28.119399700Z" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2b\n", - "After the data has been read in, the resistance and its uncertainty are to be determined for the value pairs. \n", - "First add the corresponding code to the functions in the cell below to calculate the resistance with the function <code> def uri(U,I) </code> and the uncertainty with the function def <code> def calc_sig_R(U, I, sig_I) </code>. Why does the function <code> def calc_sig_R(U, I, sig_I) </code> not have the uncertainty of the voltage as an input variable? " - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": 4, - "outputs": [], - "source": [ - "def uri(U,I):\n", - " \"\"\"\n", - " Returns the value for the resistance following Ohm's law U=R*I\n", - " :param U: voltage value\n", - " :param I: current value\n", - " :return: resistance value\n", - " \"\"\"\n", - " # Complete the code\n", - "\n", - " return \n", - "\n", - "def calc_sig_R(U, I, sig_I):\n", - " \"\"\"\n", - " Returns the value of the uncertainty of the resistance according to Ohm's law and Gaussian error propagation\n", - " :param U: voltage value\n", - " :param I: current value\n", - " :param sig_I: uncertainty of the resistance\n", - " :return: \n", - " \"\"\"\n", - " # Complete the code\n", - " return " - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-02-23T13:00:33.278431500Z", - "start_time": "2024-02-23T13:00:33.248408400Z" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Afterwards, add the code here to calculate the resistance with the function<code> def uri(U,I) </code> and add them to your pandas dataframe. Round the values to a suitable number of decimal places using the function [round](https://docs.python.org/3/library/functions.html#round)." - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": [ - "# Calculate and round the resistance\n", - "data.loc[:, \"resistance\"] = " - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - }, - "ExecuteTime": { - "end_time": "2024-02-23T13:00:43.809786300Z", - "start_time": "2024-02-23T13:00:43.786756300Z" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Now calculate the uncertainty, round it up and add it to the dataframe. Then print the dataframe to check your results." - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "# Calculate resistance uncertainty\n", - "# Remember that uncertainties shall always be rounded up!\n", - "data.loc[:, \"resistance_sig\"] = \n", - "\n", - "### Print resulting table in one line\n", - "pd.set_option(\"expand_frame_repr\", False)\n", - "print(data)" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2e\n", - "Now we have several pairs of measured values with different measurement uncertainties. In order to combine the information including the measurement uncertainties, we need to determine a suitable estimated value for the resistance. Calculate an estimation value for the resistance first using the arithmetic mean by using the function [np.mean](https://numpy.org/doc/stable/reference/generated/numpy.mean.html) and secondly using the expression for the weighted mean. The weighted mean is defined by the following formula, which you must add under the function <code> def weighted_mean(x, sig_x) </code> in the cell below:\n", - "\n", - "\n", - "\n", - "$\\left<x\\right>=\\frac{\\sum_{i=1}^N x_i / \\sigma_{i,abs}^2}{\\sum_{i=1}^N 1 / \\sigma_{i,abs}^2}$\n", - "\n", - "\n", - "Also calculate the uncertainty of the calculated mean values, in each case using the function [np.std](https://numpy.org/doc/stable/reference/generated/numpy.std.html) for the arithmetic mean and the function <code> def sig_weighted_mean(sig_x) </code> for the weighted mean. In advance, add the following formula to the function <code> def sig_weighted_mean(sig_x) </code> using [np.sqrt](https://numpy.org/doc/stable/reference/generated/numpy.sqrt.html):\n", - "\n", - "$\\sigma_{\\left<x\\right>}=\\frac{1}{\\sqrt{\\sum_{i=1}^N 1 / \\sigma_{i,abs}^2}}$\n", - "\n", - "Remember to round the values to a meaningful number of decimal places using [round](https://docs.python.org/3/library/functions.html#round) and <code> def round_up(x, decimals) </code>. \n", - "Compare your results and explain where the differences come from! \n" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 7, - "outputs": [], - "source": [ - "def weighted_mean(x, sig_x):\n", - " \"\"\"\n", - " Returns the weighted mean of variables x and their uncertainties sig_x\n", - " :param x: array with x values\n", - " :param sig_x: array with uncertainty of respective x value\n", - " :return: weighted mean\n", - " \"\"\"\n", - "\n", - " return \n", - "\n", - "def sig_weighted_mean(sig_x):\n", - " \"\"\"\n", - " Returns the uncertainty of the weighted mean of variables x and their uncertainties sig_x\n", - " :param sig_x: array with uncertainty of respective x value\n", - " :return: uncertainty of weighted mean\n", - " \"\"\"\n", - "\n", - " return " - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-02-23T13:01:31.910988Z", - "start_time": "2024-02-23T13:01:31.900940200Z" - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "# Extract the needed data from our dataframe\n", - "\n", - "n = data.shape[0] # number of measurements\n", - "R = \n", - "sig_R = \n", - "\n", - "# Calculate the arithmetic mean and its uncertainty and round your results\n", - "ar_mean = \n", - "sig_ar_mean = \n", - "\n", - "# Calculate the weighted mean and its uncertainty and round your results\n", - "w_mean = \n", - "sig_w_mean =\n", - "\n", - "# Create and print a Dataframe with results\n", - "results_2e = pd.DataFrame(np.array([[ w_mean, ar_mean], [ sig_w_mean, sig_ar_mean ]]), columns=[\"Weighted\", \"Arithmetic\"], index=[\"Mean\", \"Uncertainty\"])\n", - "print(results_2e)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2f\n", - "\n", - "In the lecture and the first part of this exercise session, we learned about the maximum likelihood method on the one hand and solved the analytical solution of the problem here using the ML method on the other.\n", - "According to Ohm's law, $I = U/R = m*U$ with $m=1/R$. This results in a linear relationship between the current and the voltage. Using the ML method, we have calculated that the following equation applies for m:\n", - "\n", - "$m = \\frac{\\sum_{i=1}^N \\frac{x_i \\cdot y_i}{\\sigma_i^2}}{\\sum_{i=1}^N \\frac{ x_i^2}{\\sigma_i^2}}$\n", - "\n", - "In this case, $x = U$, $y = I$ and $\\sigma_y = \\sigma_I$. Add the function <code> def ml_estimator(x, y, sig_y) </code> to the cell below and determine both the value for the ML estimator $m$ and then the value for the resistance. Round the value for the resistance to a meaningful number of decimal places and compare the value for the resistance with the previous ones. \n" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 9, - "outputs": [], - "source": [ - "def ml_estimator(x, y, sig_y):\n", - " \"\"\"\n", - " Returns the parameter m that is determined by using the maximum likelihood method.\n", - " :param x:\n", - " :param y:\n", - " :param sigma:\n", - " :return: m\n", - " \"\"\"\n", - "\n", - " return " - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-02-23T13:01:40.086529600Z", - "start_time": "2024-02-23T13:01:40.070463800Z" - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "# Extract needed data from dataframe\n", - "x = \n", - "y = \n", - "sig_y = \n", - "\n", - "# Calculate best estimate for the parameter m\n", - "m = \n", - "R_ml = \n", - "print(\"m = \" + str(m) + \", R = \"+str(R_ml))\n", - "\n", - "# Create and print a Dataframe with results\n", - "results_2f = pd.DataFrame(np.array([[w_mean, ar_mean, R_ml]]), columns=[\"weighted\", \"arithmetic\", \"ML-method\"])\n", - "print(results_2f)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2g\n", - "\n", - "In practice, the majority of functional relationships can no longer be determined analytically using the ML method. For these cases, the Python package [Scipy](https://scipy.org/) can be used. The [scipy.optimize.curve_fit](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html) function can be used to estimate the parameters of previously defined functional relationships for a specific data set. In the scipy documentation you will find all relevant information and steps for the implementation. \n", - "Use the function to fit a linear relationship to the measurement data according to task 2f). Compare the result for the resistance with the previous ones. " - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "# First, the linear relationship needs to be defined as a function\n", - "\n", - " \n", - "\n", - "# Use curve_fit to solve the problem and print the parameter m with its uncertainty\n", - "\n", - "\n", - "# Calculate the resistance and its uncertainty (Hint: Think about Gaussian Error Propagation!)\n", - "\n", - "\n", - "\n", - "# Create and print a Dataframe with results\n", - "results_2g = pd.DataFrame(np.array([[w_mean, ar_mean, R_ml, R_sc]]), columns=[\"weighted\", \"arithmetic\", \"ML-method\", \"Scipy Curve-Fit\"])\n", - "print(results_2g)\n" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2h\n", - "\n", - "The $\\Chi^2$ test, which is defined as follows, is suitable for determining the quality of the fit:\n", - "\n", - "$\\chi^2 = \\sum_{i=1}^N \\frac{(y_i - f(x_i, m))^2}{\\sigma_i^2}$\n", - "\n", - "Where $x=U$, $y=I$, $\\sigma_i = \\sigma_y_i$ and $f(x_i,m) = U_i/R$. Complete the function <code> def chi2_formula(x, y, sig_y, R) </code> in the cell below and calculate the $\\Chi^2/n_{d.o.f.}$ for the results from 2e) (arithmetic and weighted mean) and 2g) (Scipy Curve-Fit). Explain what the numerical values for $\\Chi^2/n_{d.o.f.}$ mean.\n", - "\n" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": 14, - "outputs": [], - "source": [ - "def chi2_formula(x, y, sig_y, R):\n", - " \"\"\"\n", - " Formula to calculate the Chi^2 value in the case of the relationship y = x/R\n", - " :param x: x values\n", - " :param y: y values\n", - " :param sig_y: uncertainty of y values\n", - " :param m: slope\n", - " :return: \n", - " \"\"\"\n", - "\n", - " return " - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-02-23T13:07:01.068534900Z", - "start_time": "2024-02-23T13:07:01.050115Z" - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "# Determine n_dof\n", - "\n", - "n = # Hint: The number of degrees of freedom is the number of measurements minus the number of parameters which were fitted \n", - "\n", - "# Calculate the Chi^2 and Chi^2/ndof for task 2f\n", - "\n", - "\n", - "# Calculate the Chi^2 and Chi^2/ndof for task 2g\n", - "\n", - "\n", - "# Print the resulting Chi^2/ndof\n", - "# Print the resulting Chi^2/ndof\n", - "print(\"Chi^2/ndof (Airthmetic Mean) = \" + str(round(chi2_ar_n, 4)))\n", - "print(\"Chi^2/ndof (Weighted Mean) = \" + str(round(chi2_weigh_n, 4)))\n", - "print(\"Chi^2/ndof (Scipy) = \" + str(round(chi2_sc_n, 4)))\n" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} -- GitLab From 9ee57d00ff9d9887c1593c9b0cd451e7cd35f8ac Mon Sep 17 00:00:00 2001 From: Amirali Mahjoob <amirali.mahjoob@rwth-aachen.de> Date: Tue, 29 Apr 2025 16:51:22 +0200 Subject: [PATCH 23/23] Delete exercise_4_A6_v1.ipynb --- Exercise_4/exercise_4_A6_v1.ipynb | 627 ------------------------------ 1 file changed, 627 deletions(-) delete mode 100644 Exercise_4/exercise_4_A6_v1.ipynb diff --git a/Exercise_4/exercise_4_A6_v1.ipynb b/Exercise_4/exercise_4_A6_v1.ipynb deleted file mode 100644 index 3e18187..0000000 --- a/Exercise_4/exercise_4_A6_v1.ipynb +++ /dev/null @@ -1,627 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "source": [ - "# DEV Exercise 6\n", - "In this Jupyter notebook we will deal with the calculation of investment and operational costs. If you have not yet installed the packages required for this exercise, run the following cell to install them." - ], - "metadata": { - "collapsed": false - }, - "id": "72ab3cf5505dbbc2" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "!pip install pandas\n", - "!pip install pandapower\n", - "!pip install simbench" - ], - "metadata": { - "collapsed": false - }, - "id": "e99cc0f65671eb71" - }, - { - "cell_type": "markdown", - "source": [ - "Now run the following cell to import the most important libraries. You can run a cell either by clicking Run on the toolbar or by pressing CTRL+RETURN." - ], - "metadata": { - "collapsed": false - }, - "id": "ddeb3acb51e3e4cd" - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "initial_id", - "metadata": { - "collapsed": true, - "ExecuteTime": { - "end_time": "2024-06-03T14:20:24.081312800Z", - "start_time": "2024-06-03T14:20:24.064701400Z" - } - }, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.simplefilter(action='ignore', category=FutureWarning)\n", - "\n", - "import pandas as pd\n", - "pd.options.display.max_rows = 10\n", - "\n", - "import pandapower as pp\n", - "import simbench as sb" - ] - }, - { - "cell_type": "markdown", - "source": [ - "### Example grid\n", - "\n", - "We will carry out the calculation using a [SimBench](https://simbench.readthedocs.io/en/stable/) example grid. SimBench is a database with synthetic grid data that maps different grid structures in low voltage. Import the grid “1-LV-rural1--0-sw” and print its properties (number and type of assets). The standard types in particular are required later for the calculation of annuities. \n" - ], - "metadata": { - "collapsed": false - }, - "id": "4963cb76c621b1bc" - }, - { - "cell_type": "code", - "execution_count": 6, - "outputs": [ - { - "data": { - "text/plain": " name std_type from_bus to_bus length_km \\\n0 LV1.101 Line 1 NAYY 4x150SE 0.6/1kV 9 2 0.055767 \n1 LV1.101 Line 2 NAYY 4x150SE 0.6/1kV 13 11 0.053576 \n2 LV1.101 Line 3 NAYY 4x150SE 0.6/1kV 6 3 0.049814 \n3 LV1.101 Line 4 NAYY 4x150SE 0.6/1kV 8 1 0.017886 \n4 LV1.101 Line 5 NAYY 4x150SE 0.6/1kV 7 10 0.016089 \n.. ... ... ... ... ... \n8 LV1.101 Line 9 NAYY 4x150SE 0.6/1kV 5 13 0.137215 \n9 LV1.101 Line 10 NAYY 4x150SE 0.6/1kV 3 0 0.132499 \n10 LV1.101 Line 12 NAYY 4x150SE 0.6/1kV 1 3 0.016207 \n11 LV1.101 Line 13 NAYY 4x150SE 0.6/1kV 12 8 0.046015 \n12 LV1.101 Line 11 NAYY 4x150SE 0.6/1kV 4 5 0.002583 \n\n r_ohm_per_km x_ohm_per_km c_nf_per_km g_us_per_km max_i_ka df \\\n0 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n1 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n2 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n3 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n4 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n.. ... ... ... ... ... ... \n8 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n9 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n10 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n11 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n12 0.2067 0.080425 829.999394 0.0 0.27 1.0 \n\n parallel type in_service voltLvl max_loading_percent subnet \n0 1 cs True 7 100.0 LV1.101 \n1 1 cs True 7 100.0 LV1.101 \n2 1 cs True 7 100.0 LV1.101 \n3 1 cs True 7 100.0 LV1.101 \n4 1 cs True 7 100.0 LV1.101 \n.. ... ... ... ... ... ... \n8 1 cs True 7 100.0 LV1.101 \n9 1 cs True 7 100.0 LV1.101 \n10 1 cs True 7 100.0 LV1.101 \n11 1 cs True 7 100.0 LV1.101 \n12 1 cs True 7 100.0 LV1.101 \n\n[13 rows x 17 columns]", - "text/html": "<div>\n<style scoped>\n .dataframe tbody tr th:only-of-type {\n vertical-align: middle;\n }\n\n .dataframe tbody tr th {\n vertical-align: top;\n }\n\n .dataframe thead th {\n text-align: right;\n }\n</style>\n<table border=\"1\" class=\"dataframe\">\n <thead>\n <tr style=\"text-align: right;\">\n <th></th>\n <th>name</th>\n <th>std_type</th>\n <th>from_bus</th>\n <th>to_bus</th>\n <th>length_km</th>\n <th>r_ohm_per_km</th>\n <th>x_ohm_per_km</th>\n <th>c_nf_per_km</th>\n <th>g_us_per_km</th>\n <th>max_i_ka</th>\n <th>df</th>\n <th>parallel</th>\n <th>type</th>\n <th>in_service</th>\n <th>voltLvl</th>\n <th>max_loading_percent</th>\n <th>subnet</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>LV1.101 Line 1</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>9</td>\n <td>2</td>\n <td>0.055767</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>1</th>\n <td>LV1.101 Line 2</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>13</td>\n <td>11</td>\n <td>0.053576</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>2</th>\n <td>LV1.101 Line 3</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>6</td>\n <td>3</td>\n <td>0.049814</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>3</th>\n <td>LV1.101 Line 4</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>8</td>\n <td>1</td>\n <td>0.017886</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>4</th>\n <td>LV1.101 Line 5</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>7</td>\n <td>10</td>\n <td>0.016089</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>...</th>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n <td>...</td>\n </tr>\n <tr>\n <th>8</th>\n <td>LV1.101 Line 9</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>5</td>\n <td>13</td>\n <td>0.137215</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>9</th>\n <td>LV1.101 Line 10</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>3</td>\n <td>0</td>\n <td>0.132499</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>10</th>\n <td>LV1.101 Line 12</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>1</td>\n <td>3</td>\n <td>0.016207</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>11</th>\n <td>LV1.101 Line 13</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>12</td>\n <td>8</td>\n <td>0.046015</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n <tr>\n <th>12</th>\n <td>LV1.101 Line 11</td>\n <td>NAYY 4x150SE 0.6/1kV</td>\n <td>4</td>\n <td>5</td>\n <td>0.002583</td>\n <td>0.2067</td>\n <td>0.080425</td>\n <td>829.999394</td>\n <td>0.0</td>\n <td>0.27</td>\n <td>1.0</td>\n <td>1</td>\n <td>cs</td>\n <td>True</td>\n <td>7</td>\n <td>100.0</td>\n <td>LV1.101</td>\n </tr>\n </tbody>\n</table>\n<p>13 rows × 17 columns</p>\n</div>" - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sb_code1 = \"1-LV-rural1--0-sw\"\n", - "net = sb.get_simbench_net(sb_code1)\n", - "net\n", - "net.line" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:21:02.405316800Z", - "start_time": "2024-06-03T14:20:58.805268800Z" - } - }, - "id": "ce2565ab7f9d932b" - }, - { - "cell_type": "markdown", - "source": [ - "Afterwards, you can plot the SimBench grid by using [the pandapower simple plotting tool](https://pandapower.readthedocs.io/en/v2.0.1/plotting/matplotlib/simple_plot.html)." - ], - "metadata": { - "collapsed": false - }, - "id": "f25c7b3b43552621" - }, - { - "cell_type": "code", - "execution_count": 5, - "outputs": [ - { - "data": { - "text/plain": "<Figure size 1000x800 with 1 Axes>", - "image/png": "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AMA0eAYdACrii1/8Yt70pjclSQ477LC89a1vzVVXXZVHHnkkc+fOzWGHHZZTTz019957b4499tisWLEiIyMjufvuu7Pzzjv39/AAwJQEOgBUxHOe85xcf/31SZJtt902S5cufdJjRkZG8trXvjYLFizIpz71qSTJ3/7t3+b9739/T88KAEyfQAeACli5cuW0Bt/22WefNcvuJ5xwQr73ve9162gAwAzxGnQAqIBly5Y96cde85rX5LLLLstvfvOb3HLLLXnf+96XbbfdNknWxHmSSZ9pBwDK4xl0AKiA+++/PwsXLlzz9le/+tW88pWvfNLjfvnLX+Z5z3te7rnnnjU/9oIXvCCXXXZZT84JAGw+z6ADQAX8y7/8y3pv77fffpM+7mlPe9qa155POOqoo7p1LABgBgl0AKiAb37zm+u9/Z73vCerVq2a9LEHHHBAGo3Gmrff+MY3dvVsAMDMEOgAUAEPPvjgem9ffvnleeELX5irrroqE69We/zxx3PBBRfkuOOOy7qvYJt4XToAULbhfh8AAJjanDlz1vv+448/nquvvjrPe97zsvvuu2ennXbKnXfeOemY3LrvCwCUyzPoAFABBx100Jrvv+Md78iuu+665u277747//Ef/zFpnO++++6ZP39+T84IAGwZgQ4AFXDGGWes+f43vvGN3HTTTfnyl7+c4447LvPmzUuz2cwOO+yQ173udTnppJPWe791X48OAJRLoANABRx66KF57nOfm6T9pdROOumkHHDAAfnBD36QRx99NGNjY1m8eHHmzZuXb3/720mS2bNn5/TTT+/nsQGAafB10AGgIu68884cddRRefjhh9f82M4775xDDz00IyMj+e53v5vVq1ev+bkLLrjAgjsAVIhAB4AKWbRoUU466aTcfffdG33MyMhIzj777Jx66qk9PBkAsKVccQeACjnooIOyePHifPazn83w8PpfjGX77bfPX/zFX+SOO+4Q5wBQQZ5BB4AKWrp0aRYsWJAkedaznpWvfe1r2X333TMyMtLfgwEAm83XQQeACrrtttvWfP/www/P0572tD6eBgCYCa64A0AFLV68eM33DzzwwD6eBACYKQIdACpo3UA/4IAD+ngSAGCmCHQAqKBbb711zfc9gw4A9SDQAaCCJp5B32677bLLLrv0+TQAwEwQ6ABQMUuXLs0999yTpH29vdFo9PlEAMBMEOgAUDHrLri73g4A9SHQAaBiLLgDQD0JdACoGAvuAFBPAh0AKsaCOwDUk0AHgIqx4A4A9STQAaBCLLgDQH0JdACoEAvuAFBfAh0AKsSCOwDUl0AHgAqx4A4A9SXQAaBCLLgDQH0JdACoEAvuAFBfAh0AKsKCOwDUm0AHgIqw4A4A9SbQAaAiLLgDQL0JdACoCAvuAFBvAh0AKsKCOwDUm0AHgIqw4A4A9SbQAaACLLgDQP0JdACoAAvuAFB/Ah0AKsCCOwDUn0AHgAqw4A4A9SfQAaACLLgDQP0JdACoAAvuAFB/Ah0ACmfBHQAGg0AHgMJZcAeAwSDQAaBwFtwBYDAIdAAonAV3ABgMAh0ACmfBHQAGg0AHgMJZcAeAwSDQAaBgFtwBYHAIdAAomAV3ABgcAh0ACmbBHQAGh0AHgIJZcAeAwSHQAaBgFtwBYHAIdAAomAV3ABgcAh0ACmXBHQAGi0AHgEJZcAeAwSLQAaBQFtwBYLAIdAAolAV3ABgsAh0ACmXBHQAGy3C/DwAArG/ZsuTGG5MbbtgpyRFZsOAXFtwBYAB4Bh0ACnHnncmf/mmy887J85+fPPzwl5L8OMuX356zzmpk6dJ+nxAA6KZGq9Vq9fsQADDoLr88OeWUZNWqZHR0w59tpdlsZL/9kssuS3bbrR8nBAC6TaADQJ8tXpwcfnjyxBPJ+PjGHzc8nDzjGckNNyRz5vTufABAb7jiDgB9dtZZyerVm47zpP3M+uLFyVe+0ptzAQC95Rl0AOijBx5oX1l/8rX2yTWbyaGHJv/xH109FgDQB55BB4A+uuqqzuM8aT/LfuON7aV3AKBeBDoA9NGjj27e+wl0AKgfgQ4AfbRgwea937bbzugxAIACCHQA6KPjjhvLyMgU63DraDTGc/DBv8vw8MoungoA6AeBDgB9MDY2lhtvvDEXXvjpHHTQT9JsdhbprVYz++9/WT7xiU/kO9/5TpYuXdrlkwIAvWLFHQB6aGxsLDfffHN++MMf5ne/+10OPPDA7Lnn8TnxxB2ydGkr4+ONjb5vszmeI49s5JvfXJ6bbro+//7v/55Vq1bloIMOytFHH52dd965h/8lAMBME+gA0AOThflxxx2XnXbaKUny7/8+luc/f3VWrJiVVmv9C27NZjI+3spTn3pPzj77npx00lFJklWrVuXGG2/Mddddl2XLlmXffffNMccckz333DONxsZDHwAok0AHgC6aKswnXHnllbnkkhszPn5GvvSl+XnggbU/d/DBybveley225X50Y9+kFe/+tXZf//91/t3LF68ONdcc00eeOCB7LrrrjnmmGPyzGc+M82mV7MBQFUIdADogk7DPEnuv//+nHvuuTn22GNz/PHHZ/Xq5Je/TJYvT7bfPtljj6TRSFqtVr72ta/lzjvvzKmnnpqFCxeu9+u0Wq384he/yDXXXJO77rorT3nKU3LUUUflkEMOycjISK/+0wGAzSTQAWAGTSfMJx5/7rnnJknOOOOMDA0NbfLXX716dc4///wsX748Z5xxRubNmzfp4+69995ce+21ufXWW7P11lvniCOOyOGHH565c+du2X8gANA1Ah0AZsB0w3zClVdemR/+8Ic544wzsssuu3T071q2bFnOPffcbLvttnnTm96U4eHhjT72t7/9ba699tr85Cc/SbPZzGGHHZajjjoq2/pC6gBQHIEOAFtgc8M8efLV9um49957c8EFF2T//ffPy172silH4R577LFcf73ldwAomUAHgM2wJWE+8f7Tudo+mUWLFuXrX/96XvCCF+TYY4/t6H0svwNAuQQ6AEzDlob5hM252j6ZK664IlddddWTlt2nYvkdAMoj0AGgAzMV5smWXW3f0FTL7p28v+V3ACiDQAeATZjJMJ/49bb0avuGOl12n4rldwDoL4EOAJOY6TCfMFNX2zc0nWX3qVh+B4D+EOgAsI5uhXkys1fbJzPdZfepWH4HgN4S6ACQ7ob5xK8/01fbJ7M5y+5TsfwOAL0h0AEYaN0O8wnduto+mc1ddp+K5XcA6C6BDsBA6lWYJ92/2r6hLV127+TXt/wOADNPoAMwUHoZ5hP/vl5cbd/QTC27T8XyOwDMHIEOwEDodZhP6OXV9g3N5LL7VCy/A8CWE+gA1Fq/wjzp/dX2ycz0svtULL8DwOYT6ADUUj/DfOLf34+r7ZPpxrL7VCy/A8D0CXQAaqXfYT6hn1fbJ9OtZfepWH4HgM4JdABqoZQwT8q42r6hbi+7d/Lvt/wOAJsm0AGotJLCfOI8pVxt31Cvlt2nYvkdACYn0AGopNLCfEJpV9s31Mtl96lYfgeA9Ql0ACql1DBPyrzaPpleL7tPxfI7ALQJdAAqoeQwT8q+2j6Zfiy7T8XyOwCDTqADULTSw3xC6VfbJ9OvZfepWH4HYFAJdACKVJUwT6pztX1D/V52n4rldwAGjUAHoChVCvOkelfbN1TKsvtULL8DMAgEOgBFqFqYT6ji1fYNlbTsPhXL7wDUmUAHoK+qGuZJda+2T6a0ZfepWH4HoI4EOgB9UeUwT6p/tX0yJS67T8XyOwB1ItAB6Kmqh/mEOlxtn0ypy+5TsfwOQB0IdAB6oi5hntTravuGSl92n4rldwCqTKAD0FV1CvOknlfbN1SVZfepWH4HoGoEOgBdUbcwn1DXq+0bqtKy+1QsvwNQFQIdgBlV1zBP6n21fTJVW3afiuV3AEon0AGYEXUO82QwrrZPporL7lOx/A5AqQQ6AFuk7mE+4YorrsjVV19d+6vtk6nqsvtULL8DUBqBDsBmGZQwT5IlS5bkvPPOG5ir7Ruq+rL7VCy/A1AKgQ7AtAxSmCeDe7V9Q3VZdp+K5XcA+kmgA9CRQQvzCYN8tX1DdVp2n4rldwD6QaADsEmDGuaJq+2Tqduy+1QsvwPQSwIdgEkNcpgnrrZvSh2X3adi+R2AXhDoAKxn0MN8gqvtm1bXZfepWH4HoJsEOgBJhPm6XG2fWt2X3adi+R2AbhDoAANOmK/P1fbODcqy+1QsvwMwUwQ6wIAS5pNztX16BmnZfSqW3wHYUgIdYMAI841ztX3zDNqy+1QsvwOwuQQ6wIAQ5pvmavuWGcRl96lYfgdgugQ6QM0J88642r7lBnXZfSqW3wHolEAHqClh3jlX22fGoC+7T8XyOwBTEegANSPMp8fV9pll2b0zlt8BmIxAB6gJYb55XG2feZbdO2f5HYB1CXSAihPmm8/V9u6x7D49lt8BSAQ6QGUJ8y3janv3WXafPsvvAINNoANUjDCfGa6294Zl981j+R1gMAl0gIoQ5jPH1fbesey+ZSy/AwwWgQ5QOGE+s1xt7z3L7jPD8jtA/Ql0gEIJ8+5wtb0/LLvPHMvvAPUl0AEKI8y7x9X2/rLsPrMsvwPUj0AHKIQw7y5X28tg2X3mWX4HqA+BDtBnwrw3XG0vh2X37rD8DlB9Ah2gT4R570xcbX/uc5+b5z//+f0+zsCz7N5dlt8BqkugA/SYMO8tV9vLZNm9Nyy/A1SLQAfoEWHeH662l8uye+9YfgeoBoEO0GXCvH9cbS+fZffesvwOUDaBDtAlwry/XG2vDsvuvWf5HaBMAh1ghgnzMrjaXi2W3fvD8jtAWQQ6wAwR5uVwtb16LLv3l+V3gDIIdIAtJMzL4mp7dVl2L4Pld4D+EegAm0mYl8nV9mqz7F4Oy+8AvSfQAaZJmJfL1fZ6sOxeFsvvAL0j0AE6JMzL5mp7vVh2L4/ld4DuE+gAUxDm1eBqe/1Ydi+T5XeA7hHoABshzKvD1fZ6suxeNsvvADNPoANsQJhXi6vt9WbZvRosvwPMDIEO8HvCvJpcba8/y+7VYfkdYMsIdGDgCfPqcrV9cFh2rxbL7wCbR6ADA0uYV5ur7YPHsnv1WH4HmB6BDgwcYV4PrrYPJsvu1WT5HaAzAh0YGMK8PlxtH1yW3avN8jvApgl0oPaEeb242o5l93qw/A7wZAIdqC1hXk+utpNYdq8Ty+8Aawl0oHaEeX252s66LLvXi+V3AIEO1IgwrzdX25mMZff6sfwODDKBDlSeMB8MrrazMZbd68nyOzCIBDpQWcJ8cLjazqZYdq83y+/AIBHoQOUI88HiajudsOw+GCy/A3Un0IHKEOaDydV2OmXZfXBYfgfqSqADxRPmg8vVdqbLsvtgsfwO1I1AB4olzAebq+1sLsvug8fyO1AXAh0ojjAncbWdLWPZfTBZfgeqTqADxRDmTHC1nS1l2X2wWX4HqkqgA30nzFmXq+3MFMvuJJbfgWoR6EDfCHMm42o7M8myOxMsvwNVINCBnhPmbIyr7XSDZXfWZfkdKJlAB3pGmLMprrbTTZbd2ZDld6BEAh3oOmFOJ1xtp9ssuzMZy+9ASQQ60DXCnE652k4vWHZnUyy/AyUQ6MCME+ZMh6vt9JJldzph+R3oF4EOzBhhzuZwtZ1es+xOpyy/A70m0IEtJszZXK620y+W3ZkOy+9Arwh0YLMJc7aEq+30m2V3psvyO9BtAh2YNmHOTHC1nRJYdmdzWH4HukWgAx0T5swUV9sphWV3toTld2CmCXRgSsKcmeRqO6Wx7M5MsPwOzASBDmyUMKcbXG2nRJbdmSmW34EtIdCBJxHmdIur7ZTMsjszyfI7sDkEOrCGMKebXG2nCiy7M9MsvwPTIdABYU5PuNpOVVh2pxssvwOdEOgwwIQ5veJqO1Vi2Z1usvwObIpAhwEkzOklV9upIsvu9ILld2BDAh0GiDCnH1xtp6osu9Mrlt+BCQIdBoAwp19cbafqLLvTS5bfAYEONSbM6SdX26kLy+70muV3GFwCHWpImFMCV9upE8vu9IPldxg8Ah0Kdf/9yT/8Q7J4cTI6muy+e/LGNyZ/8Acbfx9hTq8tW5b84z8mP/pR8sQTyY47Jq95TbLvvkvyhS+42k59bLjsvssuC/PDHyb/9E/Jgw8ms2cnRx6ZvOENyTbb9Pu01M2WLL/fckvyxS8md9+dDA8nBx6YvPnNib83hTIJdCjMY48l73hHcuGFSauVNBrtfzab7VA/5pjkgguSffdd+z7CnF4bG0s++MHkE59oh3mzmYyPJ0ND7Y/TnXd+JG94ww/y0Y+e4mo7tTGx7L5o0bb57ndflZ/9rJnh4fbvh4nfA7NnJ+9+d/KRj7R/P8BM63T5/ec/T970puSaa9phPj6+9nOKRiN5/euTT3868QUKoCwCHQqyfHly/PHJTTe1P+GbzNBQ+9mZa69N9ttPmNN74+PJa1+bfO1r7U/0JtNojGd4uJFLLmnkhS/s7fmgm/71X5fnFa+Yk/HxRlqtya8YNxrJq16V/N//2w536IZNLb/ffnty9NHtW06b+nziWc9Krrwy2Xrrnh4d2ASBDgU544zk/PM3/j/TCUNDrey66xN597vPzrJlwpze+sQnkve8Z+rHNZvJ3LnJf/5nsv323T8XdNvDDyd77pmsWNFKqzX1UNfHP95+Nh26acPl9/33Pyjvfe8pufvu4Q4+n0hOPTX5/Z4nUACBDoV46KFk112T1as7f5/3v//qvOtdTxfm9MzYWDtQ7r23s8c3GsnHPpb82Z9191zQC3/3d8n/+B/tWySdeOpTk7vuctWd3phYfv/CF5bkvPNe1vH7jYwkS5b4i1QohYtXUIh//Mepnzlf19BQK7fc8lxxTk9demnncZ60r8B/9rPdOw/00mc/23mcJ8k99yTf/373zgPrmjVrVo488sjcf/8fZWio8+ffxsban4MAZRDoUIjbb5/eaxXHxhpZtKh754HJTPfjNEl++cvp/eUTlGhsLPnVr6b3Ps1m+/cM9NKiRY2MjXX+tdJ9nEJZBDoUYnMCRvTQaxMrwJvzflBlm/Mx3Gj4c5re25yPVR+nUA6BDoXYa6+NL2JPZmgo2Wefrh0HJrXnntP/RG6nndqvcYQqGxlpfyxPx8RmA/TSPvtM76ZTq+XjFEoi0KEQf/In0/tb77Gx9uo79NLJJycLFnT++KGh5Mwzu3Yc6Kkzzpje4Nt22yUvfnH3zgOTOf306X0+MT7e/hwEKINAh0LssUfykpckw8NTP7bZTHbYIXn5y7t/LljXnDnJ297W+bMzjYZApz7e8pbOX+LRbCZvfWsye3Z3zwQbesUr2p8jdPLn9PBw+3OPPfbo/rmAzgh0KMjnP5/sssumI73ZbD+D841v+MSP/vjAB5LDD+/smcTzzkt23737Z4Je2H33zr5e9NBQcsQR7d8r0GuzZydf/3r743BTkT48nCxc2P7cAyiHQIeC7LJL8qMfJc96VvvtdUN94kum7LRTctllybHH9uGAkGTu3PaXjnrJS9pvr/tx2mi0P07nz0++/OXkjW/swwGhi970pvbH9vz57bfXfUZ94s/pl7yk/SUJ587t/fkgSY47rv25wsRuwrp/oTrxZ/ZhhyXXXdf+3AMoR6PVms4sFdALrVZy/fXJ5z6X3HDD6jzwwCM55JBt8ta3zun4Gjz0wu23t599ueKKVVmy5Hd5+tO3zamnzs5/+2/JVlv1+3TQPcuXJxdfnFx0UXL33avz2GMP5uSTt82f/dnWeeYz+306aFu9Ovm3f0v+4R+Su+5qjx0eckj75RdHHLF5X5UD6C6BDoVbsmRJzjnnnJx55plZuHBhv48Dk/JxyiDz8Q/ATHHFHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAAIdAAAACiDQAQAAoAACHQAAAAog0AEAAKAAAh0AAAAKINABAACgAMP9PgAA1bVqVfIv/5Jcdtn83HjjSVm2bF5OOy054IB+nwwAoHoEOgDT1molf//3yVlnJQ89lIyMbJ2xscNy003NfPzjyXHHJZ/+dPIHf9DvkwIAVIcr7gBMS6uVvO1tyXve047zJFm9upHx8aGMjTWSJNdckxx1VPLjH/fxoAAAFSPQAZiW885LPv/5TT9mbCx5/PHk5JOTZct6cy4AgKoT6AB0rNVKPvrRpNGY+rFjY8lvf5tceGH3zwUAUAcCHYCOXXll8stftkO9U5/6VNeOAwBQKwIdgI799KdJcxr/52i1kjvuSMbHu3cmAIC6EOgAdGx0tLPr7etqtdrX3QEA2DSBDkDHdttt+rH9lKckIyPdOQ8AQJ0IdAA6dsopybx5nT9+aCh585u7dx4AgDoR6AB0bOutk9NPb4d3J8bHk7e8pbtnAgCoC4EOwLT8z/+ZPP3pnUX6//k/yb77dv1IAAC1INABmJZtt02uuio56qj228PD6/5sK81m+zXnn/xk8u539+OEAADVJNABmLYddmhH+tVXJ696VbLbbmPZaqvlecYzRnPWWcm99yb//b/3+5QAANUyPPVDAODJGo3kmGPa35YseSDnnHNOzjzzzCxcuLDfRwMAqCTPoAMAAEABBDoAAAAUQKADAABAAQQ6AAAAFECgAwAAQAEEOgAAABRAoEPBfvWr5Pvfn53bb39GfvrT4bRa/T4RABPGxpJrrkkuuWR27rxz3zz4oE+rANgyvg46FOh730s+9rHk+99PkqckeW0uvjh55jOTd70rOf30ZNjvXoC+eOyx5JOfTD7zmeS++5L2n9Ovy8UXt/LKVybvfW/y7Gf3+ZAAVJK/6oXCnHVWcuKJyRVXPPnn7rgjedvbkj/6o+SJJ3p+NICB9+CDydFHJx/84EScrzU21sjXv54ceWTyT//Un/MBUG0CHQpy/vnJX/5l+/tjY0/++Var/e2SS5Izz+zt2QAG3dhY8uIXJ7femoyPT/6Y0dH2t9e9LvnhD3t7PgCqT6BDIUZH18b5VMbHky99KfnZz7p7JgDW+ta3kuuvn/wvUCfz4Q939zwA1I9Ah0J885vJkiWdP35oKPnc57p3HgDW96lPtf/s7cTYWPulSnfc0d0zAVAvAh0KcdllychI548fG0u+853unQeAtVqtdnB3+ux5kjQayeWXd+9MANSPQIdCPPZYpv1l1B57rDtnAWB9q1ZNL86TpNn05zQA0yPQoRDbbTf993nKU2b+HAA82axZ7W/TMTaWLFjQleMAUFMCHQrx0pe2h+I61Wwmr3hF984DwFqNRvtLXA4Pd/4+zWZy8sldOxIANSTQoRDHHZc8/entTwI70Wgkp5/e3TMBsNbb3975X6QODSUve1my667dPRMA9SLQoRCNRvLJT7b/2Umkv//9PvED6KVjj01e/vL2M+Ob0mwmc+cmf/3XvTkXAPUh0KEgJ56YXHRR+5mXya5RTvzYu9+d/NVf9fZsAIOu0UguvHDttfXJvuRas5nMn59897vJAQf09nwAVJ9Ah8K85jXJ4sXJ296WbL312h9vNlt56UvbX7Ln4x/v/Co8ADNn7tzkn/85+drX2s+or2ubbZ7IBz+Y3HZbcvTR/TkfANXWaLWm+4WdgF5ZuTK56aYHctFFX8073vGKPPOZu/T7SDCpJUuW5JxzzsmZZ56ZhQsX9vs40DMPPtj+dt11l2f58tvzzne+rd9HAqDCPIMOBZs7N9l777HsuOND2XZbf5cGUJodd2xfZT/ssO3yyCMPZtWqVf0+EgAVJtABALbQrr9f7VyyZEmfTwJAlQl0AIAttOOOO2Z4eFigA7BFBDoAwBZqNpvZeeedBToAW0SgAwDMgIULF+a+++7r9zEAqDCBDgAwA3bdddc89NBDhuIA2GwCHQBgBhiKA2BLCXQAgBlgKA6ALSXQAQBmgKE4ALaUQAcAmCGG4gDYEgIdAGCGGIoDYEsIdACAGWIoDoAtIdABAGaIoTgAtoRABwCYIYbiANgSAh0AYAYZigNgcwl0AIAZZCgOgM0l0AEAZpChOAA2l0AHAJhBhuIA2FwCHQBgBhmKA2BzCXQAgBlmKA6AzSHQAQBm2MRQ3BNPPNHvowBQIQIdAGCGTQzF3X///X0+CQBVItABAGaYoTgANodABwCYYYbiANgcAh0AoAsMxQEwXQIdAKALDMUBMF0CHQCgCwzFATBdAh0AoAsMxQEwXQIdAKALDMUBMF0CHQCgSwzFATAdAh0AoEsMxQEwHQIdAKBLDMUBMB0CHQCgSwzFATAdAh0AoEsMxQEwHQIdAKCLDMUB0CmBDgDQRYbiAOiUQAcA6CJDcQB0SqADAHSRoTgAOiXQAQC6yFAcAJ0S6AAAXWYoDoBOCHQAgC4zFAdAJwQ6AECXGYoDoBMCHQCgywzFAdAJgQ4A0GWG4gDohEAHAOgBQ3EATEWgAwD0gKE4AKYi0AEAesBQHABTEegAAD1gKA6AqQh0AIAeMBQHwFQEOgBAjxiKA2BTBDoAQI8YigNgUwQ6AECPGIoDYFMEOgBAjxiKA2BTBDoAQI8YigNgUwQ6AEAPGYoDYGMEOgBADxmKA2BjBDoAQA8ZigNgYwQ6AEAPGYoDYGMEOgBADxmKA2BjBDoAQI8ZigNgMgIdAKDHDMUBMBmBDgDQY4biAJiMQAcA6DFDcQBMRqADAPSYoTgAJiPQAQD6wFAcABsS6AAAfWAoDoANCXQAgD4wFAfAhgQ6AEAfGIoDYEMCHQCgDwzFAbAhgQ4A0CeG4gBYl0AHAOgTQ3EArEugAwD0iaE4ANYl0AEA+sRQHADrEugAAH0yMRTndegAJAIdAKCvFi5c6Bl0AJIIdACAvjIUB8AEgQ4A0EeG4gCYINABAPrIUBwAEwQ6AEAfGYoDYIJABwDoM0NxACQCHQCg7wzFAZAIdACAvjMUB0Ai0AEA+s5QHACJQAcA6DtDcQAkAh0AoAiG4gAQ6AAABTAUB4BABwAogKE4AAQ6AEABDMUBINABAApgKA4AgQ4AUAhDcQCDTaADABTCUBzAYBPoAACFMBQHMNgarVar1e9DAOt7/PHkK19JPv3pZNGi8axaNZ6nPjV5y1uGc9ppyU479fuEkIyNJd/+dvKpTyXXXjuexx8fzw47NPInfzKUP/3T5GlP6/cJoVqWLk2++MXx/M3fPJylS7dPs9nMvvsmb31r8oY3JPPn9/uEAHSbQIfC3HRT8l//a/Kb3yTNZjI+PvEzrTSbjQwNJV/4QvuTNeiXu+9uf5wuXpwMDbVjfcLQUPvj9sMfTj70oaTR6N85oSq+853kla9MVqxI2p+atX/jTPz+mT8/+cY3khe+sH9nBKD7BDoU5NZbkyOPbH+Ctm7wTObLX07++I97cy5Y14MPJocfntx7bzI6uunHfuhDyV/9VW/OBVV1+eXJiSe2/2Jr7V/Krq/ZbH+7/PLk2GN7ez4AekegQ0GOPTa57rqp47zRSObOTe6/35VHeu+tb03OPXfqj9MJixcnBxzQ3TNBVY2NJXvs0f7zfGNxPqHZTPbcM/n5z9vfB6B+/PEOhVi8OLn66s6ip9VKVq5MLryw++eCdS1bllxwQedxPjycfP7zXT0SVNq3vpXcd9/UcZ60H/OrXyWXXdb9cwHQHwIdCnHRRe2YmY4vfrE7Z4GN+X//rz1i2KnR0eRLX+reeaDqLrqovdvQqeFhfzkLUGcCHQqxZMn0Ht9qtZ91gV66//7pxUTSXqZetao754Gqu+eezm+kJO2/9PJnP0B9CXQoxOzZ01+7njWrO2eBjZk1q/2XQ9PRaEz/dggMitmzp/8+c+fO/DkAKINAh0I8+9nJ6tWdP354ODnqqO6dBybz7Gd39lrZCc1mcvDBBq1gY444Ynq3UprN9u9DAOrJijsUYvnyZOed2//s1LXXinR6q9VKDjwwuf32zp9JP++85LTTunsuqKpf/SrZZ5/Ofz81m8mvf53stlt3zwVAf3hOAwqx9dbJu9/d2TX3iWfPjzyy++eCdTUayQc+0FlMDA0lCxcmr31t988FVbX33smrXtXZs+jNZvL614tzgDrzDDoUZGwsefWrk3/+540H0NBQ+xO6a65Jdtqpt+eDCX/5l8lZZ23854eGkm22Sa66KjnooN6dC6rosceSF74wueGGjb+EpNlMjj46+d73vAYdoM48gw4FGRpKvvKVdvjsuGP7x4aHW2k2x9JotDJnTnLqqcmPfyzO6a+//dv210N/2tPabw8NtT9Om81Wms3kpS9tx4Y4h6nNm5dceWX7FtW8ee0fGxlpf0vaf9n13vcml14qzgHqzjPoUKjVq5N/+7fkuusezfXX35hTTjkkp5++IAsW9PtksFarlVx+eXLppY/m2mtvygknHJI3v3lbV3BhMy1fnnzjG8nPf95+Scl++yUvf7kwBxgUAh0Kt2TJkpxzzjk588wzs3Dhwn4fBybl4xQAYMu54g4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFGO73AYDJ/e53yYUXJtdfv00WLToljz46L29/e7L33v0+Gaz1+OPJV7+aXHbZNvnpT1+Shx6an9NOSw49tN8nAwConkar1Wr1+xDAWo8/nrz3vcm55yarViVDQ62Mj4+n0WhmfLyRF70oOfvsZPfd+31SBtn4ePK//lf729KlyfBw++O02WxmdLSRI45IPve55LDD+n1SAIDqEOhQkMcfT/7wD5NrrmkH0GSGh5OnPCX50Y88m05/tFrJaacl55+/8ccMDSWzZiWXXpocc0zvzgYAUGVegw4F+fM/33ScJ8noaPLb3yYvfvGmHwfd8rnPbTrOk2RsLHniifbH6dKlvTkXAEDVCXQoxO9+l5x3XmfRPTqa3HprcvnlXT8WrGd8PPnYxzp/7NKlyZe+1N0zAQDUhUCHQlx4Yfs1550aHm4/kwm9dMUVyV13Te99Pv3prhwFAKB2BDoU4pZb2q/b7dToaPKTn3TtODCpRYuS5jT+z9FqJXfe6eUYAACdEOhQiNHR3rwPbInR0aTRmN77tFrt16QDALBpAh0Kscce7ZDpVLOZ7LVX144Dk9p99+nH9vbbJyMj3TkPAECdCHQoxOtfP71rwOPj7S91Bb304hcn22zT+eOHhpLTT+/eeQAA6kSgQyH22Sc58cTOXofebCYLFiSvelXXjwXr2Wqr5IwzOt9LaLWSt7ylu2cCAKgLgQ4FOfvs9nXg4eGNP6bZbL8G+OKLk7lze3c2mPDhDycHHthZpH/yk8nee3f/TAAAdSDQoSB77JFcd13y9Ke331431CeWs7fZJvnWt9rPtkM/zJ+fXHllcvzx7bfX/wulVhqNZPbs9l84vf3tvT8fAEBVNVqt6cxSAb0wPp5cfnny2c+2v5Ta6Gh7EO6005JXv9oz55TjhhvaH6dXXjmahx9enr32mptTT52VN74x2W67fp8OAKBaBDoAW2zJkiU555xzcuaZZ2bhwoX9Pg4AQCW54g4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAAABQAIEOAAAABRDoAAAAUACBDgAAAAUQ6AAAAFAAgQ4AAAAFEOgAbJGlS5Mf/3gkv/zl3rn11uG0Wv0+EQBANTVaLZ9KATB9t92WfPzjyYUXJo8/vvbH99sveec7k9NPT+bM6d/5AACqRqADMG3f/GbyylcmY2PJ6Oj6P9dotP/5nOckl1ySLFjQ8+MBAFSSQAdgWq6/Pnnuc9thvqn/gwwNtR93+eVJ0wuqAACm5FMmAKblAx9Ixsc3HedJ+9n1H/wg+d73enMuAICqE+gAdOwXv0guvbQd350YGko+/enungkAoC4EOgAdu/TSta8x78TYWPsZdC+mAgCYmkAHoGOPPjr915OvXp2sWtWd8wAA1IlAB6Bj22zT+fX2CSMjyaxZ3TkPAECdCHQAOvaiF03vivvwcHLyydN7HwCAQSXQAejYnnsmJ53UHn/rxOho8o53dPdMAAB14eugAzAtP/lJctRR7deVj49v/HFDQ8kJJyTf/rZn0AEAOuEZdACm5dBDk29+M5kzZ/Jn0idG5I4/PvnqV8U5AECnBDoA0/bCFyaLFiXvelcyf/76P3foocn55yeXXJLMm9eX4wEAVJIr7gBskZUrk5/9LHn88WSnnZK99+73iQAAqkmgAwAAQAFccQcAAIACCHQAAAAogEAHAACAAgh0AAAAKIBABwAAgAIIdAAAACiAQAcAAIACCHQAAAAogEAHAACAAgh0AAAAKIBABwAAgAIIdAAAACiAQAcAAIACCHQAAAAogEAHAACAAgh0AAAAKIBABwAAgAIIdAAAACiAQAcAAIACCHQAAAAogEAHAACAAgh0AAAAKMD/BzU72j2R48omAAAAAElFTkSuQmCC" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": "<Axes: >" - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pp.plotting.simple_plot(net, show_plot=True)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:20:39.998814Z", - "start_time": "2024-06-03T14:20:39.471146800Z" - } - }, - "id": "2eb6d9517e99be23" - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2a \n", - "\n", - "To calculate the annuities, we must first determine the investment costs of the lines and transformer types. For this purpose, read these from the Excel table using [the pandas function \"read_excel\"](https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html)." - ], - "metadata": { - "collapsed": false - }, - "id": "e43234c36ca7e4ba" - }, - { - "cell_type": "code", - "execution_count": 8, - "outputs": [], - "source": [ - "line_std_types = pd.read_excel(io=\"./std_type_costs.xlsx\", index_col=[0], sheet_name=\"line_std_types\")\n", - "trafo_std_types = pd.read_excel(io=\"./std_type_costs.xlsx\", index_col=[0], sheet_name=\"trafo_std_types\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:21:58.923764700Z", - "start_time": "2024-06-03T14:21:58.809907500Z" - } - }, - "id": "c6f5410eee07a074" - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2b\n", - "Calculate the total investment cost in t=0 for the transformer and the lines.\n", - "For the equipment with unit prices the total costs can be calculated via\n", - "$C_{inv} = \\sum_{pc=1}^{n} {C_{pc}} = n \\cdot C_{pc}$" - ], - "metadata": { - "collapsed": false - }, - "id": "90aeb0e3ed2ee0d4" - }, - { - "cell_type": "code", - "execution_count": 9, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The investment costs for trafos are : 13.0 mio. €\n" - ] - } - ], - "source": [ - "trafo_name = net.trafo.std_type[0]\n", - "c_inv_trafo = len(net.trafo) * trafo_std_types.at[trafo_name, \"cost_per_piece\"]\n", - "print(f\"The investment costs for trafos are : {round(c_inv_trafo/1e6, 2)} mio. €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:02.934409600Z", - "start_time": "2024-06-03T14:22:02.914839400Z" - } - }, - "id": "527eba7f1fdd1827" - }, - { - "cell_type": "markdown", - "source": [ - "For the equipment with length related costs:\n", - "$C_{inv} = \\sum_{pc=1}^{n} {l_{pc} \\cdot C_l} = (\\sum_{pc=1}^{n} {l_{pc}}) \\cdot C_l$.\n", - "First sum up over the total line length using [pandas groupby](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html)." - ], - "metadata": { - "collapsed": false - }, - "id": "de5e30b6e28016b7" - }, - { - "cell_type": "code", - "execution_count": 10, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The line length is : 0.56 km\n" - ] - } - ], - "source": [ - "line_name = net.line.std_type[0]\n", - "sum_lines = net.line[[\"std_type\", \"length_km\"]].groupby(\"std_type\").sum().at[line_name, \"length_km\"]\n", - "print(f\"The line length is : {round(sum_lines, 3)} km\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:07.921782200Z", - "start_time": "2024-06-03T14:22:07.887759400Z" - } - }, - "id": "4731e97d3b9e66f1" - }, - { - "cell_type": "code", - "execution_count": 11, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The investment costs for lines are : 0.01 mio. €\n" - ] - } - ], - "source": [ - "c_inv_lines = sum_lines * line_std_types.at[line_name, \"cost_per_km\"]\n", - "print(f\"The investment costs for lines are : {round(c_inv_lines/1e6, 2)} mio. €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:09.292713800Z", - "start_time": "2024-06-03T14:22:09.267721Z" - } - }, - "id": "3e4b323df9b033ec" - }, - { - "cell_type": "markdown", - "source": [ - "Afterwards, calculate the total investment cost of the grid by:\n", - "$C_{grid,inv} = \\sum_{equip.} {C_{inv,equip.}}$" - ], - "metadata": { - "collapsed": false - }, - "id": "1262245f8ee4319d" - }, - { - "cell_type": "code", - "execution_count": 12, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The total grid costs are : 13.01 mio. €\n" - ] - } - ], - "source": [ - "c_total = c_inv_trafo + c_inv_lines\n", - "print(f\"The total grid costs are : {round(c_total/1e6, 2)} mio. €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:17.122947500Z", - "start_time": "2024-06-03T14:22:17.097954900Z" - } - }, - "id": "f56701e0558fd50e" - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2c\n", - "Calculate the annuity factors for the different lifetimes and components.\n", - "The annuity factors for the different lifetimes can be calculated via:\n", - "$a=\\frac{q^{T,max} \\cdot (q-1)}{q^{T,max}-1}$\n", - "\n", - "The lifetimes $T_{max}$ of the assets can be found in the Excel tables or data frames. First, define a function to calculate the annuity. This should have the lifetime and the discount rate $q = 1+r$ as input data. Usually, distribution grid operators assume an interest rate of $r=5\\%$." - ], - "metadata": { - "collapsed": false - }, - "id": "4a8f16d1e3d93bcc" - }, - { - "cell_type": "code", - "execution_count": 13, - "outputs": [], - "source": [ - "interestrate=0.05\n", - "\n", - "def annuity(n, r=interestrate):\n", - " \"\"\"Calculate the annuity factor for an asset with lifetime n years and\n", - " discount rate of r\"\"\"\n", - "\n", - " q=1+r\n", - "\n", - " if r > 0:\n", - " return (q**n*(q-1))/(q**n-1)\n", - " else:\n", - " return 1/n" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:21.141660Z", - "start_time": "2024-06-03T14:22:21.122542800Z" - } - }, - "id": "ba8c3aebb2b2edf1" - }, - { - "cell_type": "markdown", - "source": [ - "The following annuity costs then result for the components:" - ], - "metadata": { - "collapsed": false - }, - "id": "8bc1eeef24887502" - }, - { - "cell_type": "code", - "execution_count": 14, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The annuity factor for the lines is : 0.0611\n" - ] - } - ], - "source": [ - "ann_lines = annuity(line_std_types.at[line_name, \"lifetime\"])\n", - "print(f\"The annuity factor for the lines is : {round(ann_lines, 4)}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:23.374625200Z", - "start_time": "2024-06-03T14:22:23.328846900Z" - } - }, - "id": "e63a003d70957a59" - }, - { - "cell_type": "code", - "execution_count": 15, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The annuity factor for the trafos is : 0.0651\n" - ] - } - ], - "source": [ - "ann_trafo = annuity(trafo_std_types.at[trafo_name, \"lifetime\"])\n", - "print(f\"The annuity factor for the trafos is : {round(ann_trafo, 4)}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:24.896539Z", - "start_time": "2024-06-03T14:22:24.868448200Z" - } - }, - "id": "966f8b18dc754e17" - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2d\n", - "Afterwards, calculate the operating costs for the transformer and the lines. The operating costs can be found in the corresponding Excel files or data frames. The operating costs correspond to the multiplication of the investment costs with the specific operating costs from the Excel table or data frame." - ], - "metadata": { - "collapsed": false - }, - "id": "6e9b5e1600f9bf78" - }, - { - "cell_type": "code", - "execution_count": 16, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The operating costs for lines are : 156.49 €\n" - ] - } - ], - "source": [ - "c_o_lines = c_inv_lines * line_std_types.at[line_name, \"operating_cost\"]\n", - "print(f\"The operating costs for lines are : {round(c_o_lines, 2)} €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:36.659044600Z", - "start_time": "2024-06-03T14:22:36.638976800Z" - } - }, - "id": "644d4a2306910ee6" - }, - { - "cell_type": "code", - "execution_count": 17, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The operating costs for transformer are : 0.39 mio. €\n" - ] - } - ], - "source": [ - "c_o_trafo = c_inv_trafo * trafo_std_types.at[trafo_name, \"operating_cost\"]\n", - "print(f\"The operating costs for transformer are : {round(c_o_trafo/1e6, 2)} mio. €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:39.725035900Z", - "start_time": "2024-06-03T14:22:39.704038Z" - } - }, - "id": "1faf1a9504e028da" - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2e\n", - "Calculate the annual cost of the grid equipment (sum of operating and investment costs)." - ], - "metadata": { - "collapsed": false - }, - "id": "79769693879cb833" - }, - { - "cell_type": "code", - "execution_count": 18, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The annual grid costs are : 1.24 mio. €\n" - ] - } - ], - "source": [ - "c_ann_total = ann_lines * c_inv_lines + ann_trafo * c_inv_trafo + c_o_lines + c_o_trafo \n", - "print(f\"The annual grid costs are : {round(c_ann_total/1e6, 2)} mio. €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:45.654863600Z", - "start_time": "2024-06-03T14:22:45.633570100Z" - } - }, - "id": "de48aec2ff9058bf" - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2f\n", - "In the course of digitizing the distribution grids, it is advisable to equip most of the LV system equipment with measurement technology. For our system, the following assumptions can be made:\n", - "- The specific investment costs for the measurement technology system in the transformer station is 500.000€, the interest rate equals 5%/a and its lifetime equals 20 years\n", - "- Every grid customer within our grid will also be equipped with a smart meter. As the smart meters belong to the metering point operator and not the distribution grid operator, there are no investment costs here.\n", - "- Because metering technology allows the grid to operate more efficiently, the lifetimes of all other technologies increase by 5 years\n", - "\n", - "Calculate the new annuity of investment costs for the total system with the measurement technology" - ], - "metadata": { - "collapsed": false - }, - "id": "ee9bcd85e1c42abc" - }, - { - "cell_type": "code", - "execution_count": 19, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The new annual grid costs are : 1.22 mio. €\n" - ] - } - ], - "source": [ - "c_ann_trafo = 1 * trafo_std_types.at[trafo_name, \"cost_per_piece\"] * annuity(trafo_std_types.at[trafo_name, \"lifetime\"] + 5)\n", - "c_ann_lines = sum_lines * line_std_types.at[line_name, \"cost_per_km\"] * annuity(line_std_types.at[line_name, \"lifetime\"] + 5)\n", - "\n", - "c_inv_measure = 500000\n", - "lifetime_measure = 20\n", - "c_ann_measure = annuity(lifetime_measure) * c_inv_measure\n", - "\n", - "c_ann_total_new = c_ann_trafo + c_ann_lines + c_o_trafo + c_o_lines + c_ann_measure\n", - "print(f\"The new annual grid costs are : {round(c_ann_total_new/1e6, 2)} mio. €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:48.991815900Z", - "start_time": "2024-06-03T14:22:48.974735500Z" - } - }, - "id": "e9bf09de56cfedb1" - }, - { - "cell_type": "markdown", - "source": [ - "### Task 2g\n", - "What are the maximum annual operating costs for the measurement equipment in order to still be cheaper than without measurement equipment?" - ], - "metadata": { - "collapsed": false - }, - "id": "51cf92fb26790ff" - }, - { - "cell_type": "code", - "execution_count": 20, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The maximum annual operating costs can be : 11651.6 €\n" - ] - } - ], - "source": [ - "c_o_measure = c_ann_total - c_ann_total_new\n", - "print(f\"The maximum annual operating costs can be : {round(c_o_measure, 2)} €\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-06-03T14:22:54.454657700Z", - "start_time": "2024-06-03T14:22:54.436729800Z" - } - }, - "id": "b749b6d14d16ff43" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [], - "metadata": { - "collapsed": false - }, - "id": "dfd9b25d20fc7b6c" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} -- GitLab