{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "8rOoC1NVjRcT" }, "source": [ "# Simple Time Series Example" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "bSEcFiPijRcb" }, "source": [ "This tutorial shows how a simple time series simulation is performed with the timeseries and control module in pandapower. A time series calculation requires the minimum following inputs:\n", "* pandapower net\n", "* the time series (in a pandas Dataframe for example)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "YquzqXkKjRcd" }, "source": [ "First we need some imports. Specific for this example are:\n", "* ConstControl -> \"constant\" controllers, which change the P and Q values of sgens and loads\n", "* DFData -> The Dataframe Datasource. This Dataframe holds the time series to be calculated\n", "* OutputWriter -> The output writer, which is required to write the outputs to the hard disk\n", "* run_timeseries -> the \"main\" time series function, which basically calls the controller functions (to update the P, Q of the ConstControllers) and runpp." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "Dx9ZKvbfjRcg" }, "outputs": [], "source": [ "import os\n", "import tempfile\n", "import pandas as pd\n", "import numpy as np\n", "from pandapower.timeseries import DFData, OutputWriter, run_timeseries\n", "from pandapower.control import ConstControl\n", "from pandapower.create import (\n", " create_empty_network,\n", " create_bus,\n", " create_ext_grid,\n", " create_line,\n", " create_transformer,\n", " create_sgen,\n", " create_load,\n", "\n", ")\n", "from pandapower.run import set_user_pf_options\n", "\n", "rng = np.random.default_rng(10)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "NJj7q_srjRcs" }, "source": [ "First we look at the time series example function. It follows these steps:\n", "1. create a simple test net\n", "2. create the datasource (which contains the time series P values)\n", "3. create the controllers to update the P values of the load and the sgen\n", "4. define the output writer and desired variables to be saved\n", "5. call the main time series function to calculate the desired results" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "E5i2ezcDjRcw" }, "outputs": [], "source": [ "def timeseries_example(output_dir):\n", " # 1. create test net\n", " net = simple_test_net()\n", "\n", " # 2. create (random) data source\n", " n_timesteps = 10\n", " profiles, ds = create_data_source(n_timesteps)\n", " # 3. create controllers (to control P values of the load and the sgen)\n", " create_controllers(net, ds)\n", "\n", " # time steps to be calculated. Could also be a list with non-consecutive time steps\n", " time_steps = range(0, n_timesteps)\n", "\n", " # 4. the output writer with the desired results to be stored to files.\n", " ow = create_output_writer(net, time_steps, output_dir=output_dir)\n", "\n", " # 5. the main time series function\n", " run_timeseries(net, time_steps)\n", " print(net.res_line.loading_percent)\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "xhzr8EE5jRc3" }, "source": [ "We start by creating a simple example pandapower net consisting of five buses, a transformer, three lines, a load and a sgen. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "x8hpgqhQjRc5" }, "outputs": [], "source": [ "def simple_test_net():\n", " \"\"\"\n", " simple net that looks like:\n", "\n", " ext_grid b0---b1 trafo(110/20) b2----b3 load\n", " |\n", " |\n", " b4 sgen\n", " \"\"\"\n", " net = create_empty_network()\n", " set_user_pf_options(net, init_vm_pu = \"flat\", init_va_degree = \"dc\", calculate_voltage_angles=True)\n", "\n", " b0 = create_bus(net, 110)\n", " b1 = create_bus(net, 110)\n", " b2 = create_bus(net, 20)\n", " b3 = create_bus(net, 20)\n", " b4 = create_bus(net, 20)\n", "\n", " create_ext_grid(net, b0)\n", " create_line(net, b0, b1, 10, \"149-AL1/24-ST1A 110.0\")\n", " create_transformer(net, b1, b2, \"25 MVA 110/20 kV\", name='tr1')\n", " create_line(net, b2, b3, 10, \"184-AL1/30-ST1A 20.0\")\n", " create_line(net, b2, b4, 10, \"184-AL1/30-ST1A 20.0\")\n", "\n", " create_load(net, b3, p_mw=15., q_mvar=10., name='load1')\n", " create_sgen(net, b4, p_mw=20., q_mvar=0.15, name='sgen1')\n", "\n", " return net" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "9CcyC2mgjRc_" }, "source": [ "The data source is a simple pandas DataFrame. It contains random values for the load and the sgen P values (\"profiles\"). Of course your time series values should be loaded from a file later on.\n", "Note that the profiles are identified by their column name (\"load1_p\", \"sgen1_p\"). You can choose here whatever you prefer.\n", "The DFData(profiles) converts the Dataframe to the required format for the controllers. Note that the controller" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "KVrcajmqjRdB" }, "outputs": [], "source": [ "def create_data_source(n_timesteps=24):\n", " profiles = pd.DataFrame()\n", " \n", " profiles['load1_p'] = rng.random(n_timesteps) * 15.\n", " profiles['sgen1_p'] = rng.random(n_timesteps) * 20.\n", "\n", " ds = DFData(profiles)\n", "\n", " return profiles, ds" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "_29FDhugjRdJ" }, "source": [ "create the controllers by telling the function which element_index belongs to which profile. In this case we map:\n", "* first load in dataframe (element_index=[0]) to the profile_name \"load1_p\"\n", "* first sgen in dataframe (element_index=[0]) to the profile_name \"sgen1_p\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "C7jNYZYhjRdN" }, "outputs": [], "source": [ "def create_controllers(net, ds):\n", " ConstControl(net, element='load', variable='p_mw', element_index=[0],\n", " data_source=ds, profile_name=[\"load1_p\"])\n", " ConstControl(net, element='sgen', variable='p_mw', element_index=[0],\n", " data_source=ds, profile_name=[\"sgen1_p\"])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "kDA6xHDWjRdT" }, "source": [ "create the output writer. Instead of saving the whole net (which takes a lot of time), we extract only pre defined outputs.\n", "In this case we:\n", "* save the results to \"../timeseries/tests/outputs\" \n", "* write the results to \".xls\" Excel files. (Possible are: .json, .p, .csv)\n", "* log the variables \"p_mw\" from \"res_load\", \"vm_pu\" from \"res_bus\" and two res_line values." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "GlttGzEHjRdV" }, "outputs": [], "source": [ "def create_output_writer(net, time_steps, output_dir):\n", " ow = OutputWriter(net, time_steps, output_path=output_dir, output_file_type=\".xlsx\", log_variables=[])\n", " # these variables are saved to the harddisk after / during the time series loop\n", " ow.log_variable('res_load', 'p_mw')\n", " ow.log_variable('res_bus', 'vm_pu')\n", " ow.log_variable('res_line', 'loading_percent')\n", " ow.log_variable('res_line', 'i_ka')\n", " return ow" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "DAIvq_bUjRdb" }, "source": [ "Now lets execute the code." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "wTlSALR0jRdd", "outputId": "959014ba-8db7-412b-d425-f2af199207f0" }, "outputs": [], "source": [ "output_dir = os.path.join(tempfile.gettempdir(), \"time_series_example\")\n", "print(\"Results can be found in your local temp folder: {}\".format(output_dir))\n", "if not os.path.exists(output_dir):\n", " os.mkdir(output_dir)\n", "timeseries_example(output_dir)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "v8-ZYJFujRdk" }, "source": [ "If everything works you should have the desired results the output_folder, which is the temporary folder of your operating system (see print statement above)." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "EzTC_NnRjRdn" }, "source": [ "## Plot the result\n", "Let's read the result from the disk and plot it" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "DhVd7-3ejRdp", "outputId": "101d40f1-78fc-485d-eac9-70b90baf3abf" }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "%matplotlib inline \n", "\n", "x_label = \"time step\"\n", "\n", "# voltage results\n", "vm_pu_file = os.path.join(output_dir, \"res_bus\", \"vm_pu.xlsx\")\n", "vm_pu = pd.read_excel(vm_pu_file, index_col=0)\n", "vm_pu.plot(label=\"vm_pu\")\n", "plt.xlabel(x_label)\n", "plt.ylabel(\"voltage mag. [p.u.]\")\n", "plt.title(\"Voltage Magnitude\")\n", "plt.grid()\n", "plt.show()\n", "\n", "# line loading results\n", "ll_file = os.path.join(output_dir, \"res_line\", \"loading_percent.xlsx\")\n", "line_loading = pd.read_excel(ll_file, index_col=0)\n", "line_loading.plot(label=\"line_loading\")\n", "plt.xlabel(x_label)\n", "plt.ylabel(\"line loading [%]\")\n", "plt.title(\"Line Loading\")\n", "plt.grid()\n", "plt.show()\n", "\n", "# load results\n", "load_file = os.path.join(output_dir, \"res_load\", \"p_mw.xlsx\")\n", "load = pd.read_excel(load_file, index_col=0)\n", "load.plot(label=\"load\")\n", "plt.xlabel(x_label)\n", "plt.ylabel(\"P [MW]\")\n", "plt.grid()\n", "plt.show()" ] } ], "metadata": { "colab": { "name": "time_series.ipynb", "provenance": [] }, "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" } }, "nbformat": 4, "nbformat_minor": 1 }