{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Conduit Transformers\n",
    "\n",
    "The conduit transformers library is the original framework for making power engineering computations and can be used for fast and efficient one-off computations on an individual stream or set of streams. These functions are necessarily more manual than the graph based method of computation, but allows you to work a bit more quickly than you might with the data flow. However, it is strongly recommended that you use the graph based computation framework wherever possible!\n",
    "\n",
    "The transformer API is as follows:\n",
    "\n",
    "\n",
    "```python\n",
    "\n",
    "def transformer(data, tags, annotations):\n",
    "    return data, tags, annotations\n",
    "```\n",
    "\n",
    "All transformers take data as either a `pd.Series` or `pd.DataFrame` and tags and annotations either as dictionaries with the tags and annotations for a single stream, or a list of dictionaries if there are multiple streams in a data frame. The transformer then returns the computed data along with new tags and annotations that describe the returned data stream or streams."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import btrdb\n",
    "import pandas as pd\n",
    "\n",
    "from conduit.constants import *\n",
    "from btrdb.utils.timez import ns_delta\n",
    "from conduit.transformers.phasor import *\n",
    "from conduit.stream import points_to_series\n",
    "from conduit.transformers.conversions import * "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'majorVersion': 5, 'build': '5.6.3', 'proxy': {'proxyEndpoints': []}}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "db = btrdb.connect(profile=\"dominion.predictivegrid.com\")\n",
    "db.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Selection and Materialization\n",
    "\n",
    "Conduit transformers require you to materialize your data into a `pd.Series` or `pd.DataFrame` before you can begin to work with them. To help with this, you can use the `conduit.stream.points_to_series` function to convert a single stream query into a time-indexed pandas data structure. This function can handle either raw values queries or windows queries that return statistical aggregate points. \n",
    "\n",
    "### Values to Series\n",
    "\n",
    "Convert a `stream.values()` query to a `pd.Series` as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    67837.398438\n",
       "2019-09-25 12:00:00.033333100    67878.062500\n",
       "2019-09-25 12:00:00.066666300    67845.203125\n",
       "2019-09-25 12:00:00.100000200    67860.359375\n",
       "2019-09-25 12:00:00.133333200    67881.507812\n",
       "Name: 11ed9a21-4371-5aa1-8085-b990869d0b51, dtype: float64"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "stream = db.stream_from_uuid(\"11ed9a21-4371-5aa1-8085-b990869d0b51\") # Northeast Carver 3 Ean VPHM\n",
    "series = points_to_series(\n",
    "            stream.values(\"2019-09-25T12:00:00.000\", \"2019-09-25T12:01:00.000\"),\n",
    "            name=str(stream.uuid),\n",
    "         )\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that you can pass the result of the `stream.values()` query directly to `points_to_series` along with other arguments such as `name` and `dtype` that add metadata to the series object. Most commonly, we simply pass the stream UUID to the `name` argument to easily identify it, but you can pass whatever identifying label you wish. \n",
    "\n",
    "Note also that the timestamps are automatically converted into `np.datetime64` objects, which allow you to do easy time series analysis on the data stream. For more on these arguments, use `help(points_to_series)`.\n",
    "\n",
    "### Windows and Aligned Windows to Series \n",
    "\n",
    "The `points_to_series` function can also convert queries that return statistical points such as `stream.windows` and `stream.aligned_windows`. To do this you need to specify which statistical aggregate you would like returned, which is by default the `mean`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00    67909.286458\n",
       "2019-09-25 12:00:05    67907.396560\n",
       "2019-09-25 12:00:10    67861.438227\n",
       "2019-09-25 12:00:15    67841.727961\n",
       "2019-09-25 12:00:20    67973.322553\n",
       "Name: 11ed9a21-4371-5aa1-8085-b990869d0b51 (mean), dtype: float64"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series = points_to_series(\n",
    "            stream.windows(\"2019-09-25T12:00:00.000\", \"2019-09-25T12:01:00.000\", ns_delta(seconds=5), depth=30),\n",
    "            name=\"{} (mean)\".format(stream.uuid)\n",
    "         )\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you would like the number of points returned, you could use `count` as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 11:59:58.356652032    129\n",
       "2019-09-25 12:00:02.651619328    129\n",
       "2019-09-25 12:00:06.946586624    129\n",
       "2019-09-25 12:00:11.241553920    129\n",
       "2019-09-25 12:00:15.536521216    128\n",
       "Name: 11ed9a21-4371-5aa1-8085-b990869d0b51 (count), dtype: int64"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series = points_to_series(\n",
    "            stream.aligned_windows(\"2019-09-25T12:00:00.000\", \"2019-09-25T12:01:00.000\", pointwidth=32),\n",
    "            agg=\"count\", name=\"{} (count)\".format(stream.uuid)\n",
    "         )\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Multiple Series to DataFrames\n",
    "\n",
    "If you would like to combine multiple series into a `pd.DataFrame`, the simplest way to do this using the manual transformer method is to use `pd.concat` which will join multiple series on their index. For example, to compose a phasor, you might do this as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "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>VPHM</th>\n",
       "      <th>VPHA</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.000000000</th>\n",
       "      <td>67837.398438</td>\n",
       "      <td>-75.875275</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.033333100</th>\n",
       "      <td>67878.062500</td>\n",
       "      <td>-75.910896</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.066666300</th>\n",
       "      <td>67845.203125</td>\n",
       "      <td>-75.969505</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.100000200</th>\n",
       "      <td>67860.359375</td>\n",
       "      <td>-76.082619</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.133333200</th>\n",
       "      <td>67881.507812</td>\n",
       "      <td>-76.084686</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                       VPHM       VPHA\n",
       "2019-09-25 12:00:00.000000000  67837.398438 -75.875275\n",
       "2019-09-25 12:00:00.033333100  67878.062500 -75.910896\n",
       "2019-09-25 12:00:00.066666300  67845.203125 -75.969505\n",
       "2019-09-25 12:00:00.100000200  67860.359375 -76.082619\n",
       "2019-09-25 12:00:00.133333200  67881.507812 -76.084686"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vphm = db.stream_from_uuid(\"11ed9a21-4371-5aa1-8085-b990869d0b51\") # Northeast Carver 3 Ean VPHM\n",
    "vpha = db.stream_from_uuid(\"8b696776-4a47-54b6-ae3b-4ff6bd218a3f\") # Northeast Carver 3 Ean VPHA\n",
    "\n",
    "START = \"2019-09-25T12:00:00.000\"\n",
    "END = \"2019-09-25T12:01:00.000\"\n",
    "\n",
    "df = pd.concat([\n",
    "    points_to_series(vphm.values(START, END), name=\"VPHM\"),\n",
    "    points_to_series(vpha.values(START, END), name=\"VPHA\"),\n",
    "], axis=1)\n",
    "\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that `axis=1` is used to ensure the columns are joined instead of simply appending the rows together. This function relies on the index to align the columns; if there is a timestamp misalignment then `pd.concat` will fill in the missing column with `np.nan`. This can cause problems in some computations, so be sure to check if there are NaNs in your data as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "VPHM    0\n",
       "VPHA    0\n",
       "dtype: int64"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.isna().sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Warning**: Always keep in mind that the tags and annotations sent to transformers must be in the same order as the columns in the data frames you compose. This will often lead to functions in your code that look like this:\n",
    "\n",
    "```python\n",
    "def myvalues(streams, start, end):\n",
    "    df = pd.concat([\n",
    "        points_to_series(stream.values(start, end), name=str(stream.uuid))\n",
    "        for stream in streams\n",
    "    ], axis=1)\n",
    "    \n",
    "    tags = [stream.tags() for stream in streams]\n",
    "    annotations = [stream.annotations()[0] for stream in streams]\n",
    "    \n",
    "    return df, tags, annotations\n",
    "```\n",
    "\n",
    "However, if you find yourself doing this a lot, I would strongly recommend using the Conduit data flow API instead of the transformer API."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conversions\n",
    "\n",
    "The conversions transformers take a stream as input and then apply a conversion to the data and metadata. These functions take a single stream as input and output a single stream as output.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Test data for conversions\n",
    "vphm = db.stream_from_uuid(\"11ed9a21-4371-5aa1-8085-b990869d0b51\") # Northeast Carver 3 Ean VPHM\n",
    "vpha = db.stream_from_uuid(\"8b696776-4a47-54b6-ae3b-4ff6bd218a3f\") # Northeast Carver 3 Ean VPHA\n",
    "iphm = db.stream_from_uuid(\"994c4914-1a7d-51d2-b7cc-8590787dc250\") # Northeast Carver 3 Ia IPHM\n",
    "ipha = db.stream_from_uuid(\"d699e645-09ce-51da-9e16-825d1771cc44\") # Northeast Carver 3 Ia IPHA\n",
    "\n",
    "START = \"2019-09-25T12:00:00.000\"\n",
    "END = \"2019-09-25T12:01:00.000\"\n",
    "\n",
    "\n",
    "def fetch_values(stream, start=START, end=END):\n",
    "    series = points_to_series(stream.values(start, end), name=str(stream.uuid))\n",
    "    return series, stream.tags(), stream.annotations()[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Per Unit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function per_unit in module conduit.transformers.conversions:\n",
      "\n",
      "per_unit(series, tags, annotations, base_kv=None)\n",
      "    Convert a magnitude stream into per-unit quantities.\n",
      "    \n",
      "    The Per Unit system is a unit-less domain that allows many common power\n",
      "    engineering calculations to be carried out in a much simpler fashion. Voltage\n",
      "    and current magnitudes are converted using different formulas that are\n",
      "    determined by the specified stream units in the tags.\n",
      "    \n",
      "    Voltage is converted to Per Unit by dividing the volts by the Base KV.\n",
      "    Base KV can be set to anything but is generally mapped to the voltage level of\n",
      "    the network. For example a 500kV network has a Base KV of 500. Base KV is\n",
      "    represented in Line-to-Line KV.\n",
      "    \n",
      "    Conversion of voltage magnitudes to per unit is applied differently based on\n",
      "    the starting units. Voltage magnitudes are traditionally reported in\n",
      "    line-to-neutral volts but are commonly displayed in line-to-line volts. The\n",
      "    difference between these two is a SQRT_3 multiplication.\n",
      "    \n",
      "    Current is converted to Per Unit in a similar fashion, however the conversion\n",
      "    requires a constant System Base MVA value. The nearly ubiquitous rule of thumb\n",
      "    is 100 MVA for System Base, which is used here.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    series : pd.Series\n",
      "        The input stream for the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags must contain the unit of the streams, tags are updated with the\n",
      "        new stream units as PER_UNIT after successful computation.\n",
      "    \n",
      "    annotations : Annotations\n",
      "        May contain the ``base_kv`` parameter so it does not have to be specified.\n",
      "    \n",
      "    base_kv : float, default: None\n",
      "        The Base KV of the stream for Per-Unit conversion. If None, the value is\n",
      "        discovered from the annotations.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        The output stream following the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags updated with the new units\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations updated with the base_kv and stream type.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(per_unit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    1.609680\n",
       "2019-09-25 12:00:00.033333100    1.600887\n",
       "2019-09-25 12:00:00.066666300    1.584741\n",
       "2019-09-25 12:00:00.100000200    1.617867\n",
       "2019-09-25 12:00:00.133333200    1.604629\n",
       "Name: 994c4914-1a7d-51d2-b7cc-8590787dc250, dtype: float64"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = per_unit(*fetch_values(iphm), base_kv=500)\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'distiller': '',\n",
      " 'ingress': 'dfr_72_80',\n",
      " 'name': 'DFR!PMU-NOR2_237-PM40',\n",
      " 'unit': 'Per Unit'}\n"
     ]
    }
   ],
   "source": [
    "tags.pprint()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'acronym': 'IPHM',\n",
      " 'base_kv': 500,\n",
      " 'description': 'Northeast DFR 2 CH 40: Carver 3 Ia',\n",
      " 'devacronym': 'DFR!PMU-NOR2_237',\n",
      " 'enabled': True,\n",
      " 'id': '6e76eb5b-a352-4f16-97e7-22ae3b1d9325',\n",
      " 'internal': True,\n",
      " 'label': 'Northeast Carver 3 Ia',\n",
      " 'measurement_type': 'Current Magnitude',\n",
      " 'phase': 'A',\n",
      " 'reference': 'DFR!PMU-NOR2_237-PM40',\n",
      " 'type': 'I'}\n"
     ]
    }
   ],
   "source": [
    "annotations.pprint()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    0.234996\n",
       "2019-09-25 12:00:00.033333100    0.235137\n",
       "2019-09-25 12:00:00.066666300    0.235023\n",
       "2019-09-25 12:00:00.100000200    0.235075\n",
       "2019-09-25 12:00:00.133333200    0.235148\n",
       "Name: 11ed9a21-4371-5aa1-8085-b990869d0b51, dtype: float64"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = fetch_values(vphm)\n",
    "\n",
    "# Update voltage units to line to neutral\n",
    "tags[UNIT] = VOLTS_L_N\n",
    "\n",
    "series, tags, annotations = per_unit(series, tags, annotations, base_kv=500)\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Line to Line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function line_to_line in module conduit.transformers.conversions:\n",
      "\n",
      "line_to_line(series, tags, annotations, base_kv=None)\n",
      "    Converts a voltage magnitude into Line-to-Line volts.\n",
      "    \n",
      "    Voltage magnitudes may begin as Per Unit, Line-to-Neutral or Line-to-Line.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    series : pd.Series\n",
      "        The input stream for the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags must contain the unit of the streams, tags are updated with the\n",
      "        new stream units as VOLTS_L_L after successful computation.\n",
      "    \n",
      "    annotations : Annotations\n",
      "        May contain the ``base_kv`` parameter so it does not have to be specified.\n",
      "    \n",
      "    base_kv : float, default: None\n",
      "        The Base KV of the stream for Per-Unit conversion. If None, the value is\n",
      "        discovered from the annotations.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        The output stream following the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags updated with the new units\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations updated with the base_kv and stream type.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(line_to_line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    117497.820747\n",
       "2019-09-25 12:00:00.033333100    117568.252969\n",
       "2019-09-25 12:00:00.066666300    117511.338862\n",
       "2019-09-25 12:00:00.100000200    117537.590257\n",
       "2019-09-25 12:00:00.133333200    117574.220426\n",
       "Name: 11ed9a21-4371-5aa1-8085-b990869d0b51, dtype: float64"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Converting per-unit to line to line\n",
    "# Note that base_kv is in the annotations now!\n",
    "series, tags, annotations = line_to_line(series, tags, annotations)\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'distiller': '',\n",
      " 'ingress': 'dfr_72_80',\n",
      " 'name': 'DFR!PMU-NOR2_237-PM37',\n",
      " 'unit': 'Voltage Line-to-Line'}\n"
     ]
    }
   ],
   "source": [
    "tags.pprint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Line to Neutral"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function line_to_neutral in module conduit.transformers.conversions:\n",
      "\n",
      "line_to_neutral(series, tags, annotations, base_kv=None)\n",
      "    Converts a voltage magnitude into Line-to-Neutral volts.\n",
      "    \n",
      "    Voltage magnitudes may begin as Per Unit, Line-to-Neutral or Line-to-Line.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    series : pd.Series\n",
      "        The input stream for the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags must contain the unit of the streams, tags are updated with the\n",
      "        new stream units as VOLTS_L_N after successful computation.\n",
      "    \n",
      "    annotations : Annotations\n",
      "        May contain the ``base_kv`` parameter so it does not have to be specified.\n",
      "    \n",
      "    base_kv : float, default: None\n",
      "        The Base KV of the stream for Per-Unit conversion. If None, the value is\n",
      "        discovered from the annotations.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        The output stream following the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags updated with the new units\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations updated with the base_kv and stream type.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(line_to_neutral)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    67837.398437\n",
       "2019-09-25 12:00:00.033333100    67878.062500\n",
       "2019-09-25 12:00:00.066666300    67845.203125\n",
       "2019-09-25 12:00:00.100000200    67860.359375\n",
       "2019-09-25 12:00:00.133333200    67881.507812\n",
       "Name: 11ed9a21-4371-5aa1-8085-b990869d0b51, dtype: float64"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Hopefully this equals our original data!\n",
    "# Note that base_kv is in the annotations now!\n",
    "series, tags, annotations = line_to_neutral(series, tags, annotations)\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Amps\n",
    "\n",
    "If we need to convert IPHM per-unit back to amps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function amps in module conduit.transformers.conversions:\n",
      "\n",
      "amps(series, tags, annotations, base_kv=None)\n",
      "    Converts a current magnitude from Per Unit into Amps.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    series : pd.Series\n",
      "        The input stream for the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags must contain the unit of the streams, tags are updated with the\n",
      "        new stream units as AMPS after successful computation.\n",
      "    \n",
      "    annotations : Annotations\n",
      "        May contain the ``base_kv`` parameter so it does not have to be specified.\n",
      "    \n",
      "    base_kv : float, default: None\n",
      "        The Base KV of the stream for Per-Unit conversion. If None, the value is\n",
      "        discovered from the annotations.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        The output stream following the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags updated with the new units\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations updated with the base_kv and stream type.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(amps)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Calibrate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function calibrate in module conduit.transformers.conversions:\n",
      "\n",
      "calibrate(series, tags, annotations, rcf=None, pacf=None)\n",
      "    Calibrates phasor measurement components by applying a multiplicative correction\n",
      "    (ratio correction factor - RCF) for phasor magnitudes and an additive correction\n",
      "    factor (phase angle correction factor - PACF) to phasor angles.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    series : pd.Series\n",
      "        The input stream for the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags must contain the unit of the streams.\n",
      "    \n",
      "    annotations : Annotations\n",
      "        May contain the ``rcf`` and ``pacf`` parameters so they do not have to be\n",
      "        specified directly.\n",
      "    \n",
      "    rcf : float, default: None\n",
      "        The Ratio Correction Factor, a multiplicative correction factor for phasor\n",
      "        magnitudes. If None, the value is discovered from the annotations.\n",
      "    \n",
      "    pacf : float, default: None\n",
      "        The Phase Angle Correction Factor, an additive correction factor for phasor\n",
      "        angles. If None, the value is discovered from the annotations.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        The output stream following the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags updated with the new units\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations updated with the calibration factor and stream type.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(calibrate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    3391.869922\n",
       "2019-09-25 12:00:00.033333100    3393.903125\n",
       "2019-09-25 12:00:00.066666300    3392.260156\n",
       "2019-09-25 12:00:00.100000200    3393.017969\n",
       "2019-09-25 12:00:00.133333200    3394.075391\n",
       "Name: 11ed9a21-4371-5aa1-8085-b990869d0b51, dtype: float64"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = calibrate(*fetch_values(vphm), rcf=0.05)\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000   -75.755275\n",
       "2019-09-25 12:00:00.033333100   -75.790896\n",
       "2019-09-25 12:00:00.066666300   -75.849505\n",
       "2019-09-25 12:00:00.100000200   -75.962619\n",
       "2019-09-25 12:00:00.133333200   -75.964686\n",
       "Name: 8b696776-4a47-54b6-ae3b-4ff6bd218a3f, dtype: float64"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = calibrate(*fetch_values(vpha), pacf=0.12)\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'distiller': '',\n",
      " 'ingress': 'dfr_72_80',\n",
      " 'name': 'DFR!PMU-NOR2_237-PA37',\n",
      " 'unit': 'VPHA'}\n"
     ]
    }
   ],
   "source": [
    "tags.pprint()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'acronym': 'VPHA',\n",
      " 'description': 'Northeast DFR 2 CH 37: Carver 3 Ean',\n",
      " 'devacronym': 'DFR!PMU-NOR2_237',\n",
      " 'enabled': True,\n",
      " 'id': '24b074cc-20e7-477a-a7a3-8cf02459c487',\n",
      " 'internal': True,\n",
      " 'label': 'Northeast Carver 3 Ean',\n",
      " 'measurement_type': 'Voltage Angle',\n",
      " 'pacf': 0.12,\n",
      " 'phase': 'A',\n",
      " 'reference': 'DFR!PMU-NOR2_237-PA37',\n",
      " 'type': 'V'}\n"
     ]
    }
   ],
   "source": [
    "annotations.pprint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Radians"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function radians in module conduit.transformers.conversions:\n",
      "\n",
      "radians(series, tags, annotations)\n",
      "    Converts phasor angle into radians.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    series : pd.Series\n",
      "        The input stream for the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags must contain the unit of the streams, tags are updated with the\n",
      "        new stream units as RADIANS after successful computation.\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations belonging to the stream\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        The output stream following the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags updated with the new units\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations belonging to the stream\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(radians)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000   -1.639941\n",
       "2019-09-25 12:00:00.033333100   -1.642482\n",
       "2019-09-25 12:00:00.066666300   -1.632414\n",
       "2019-09-25 12:00:00.100000200   -1.649094\n",
       "2019-09-25 12:00:00.133333200   -1.641189\n",
       "Name: d699e645-09ce-51da-9e16-825d1771cc44, dtype: float64"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = radians(*fetch_values(ipha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Degrees"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function degrees in module conduit.transformers.conversions:\n",
      "\n",
      "degrees(series, tags, annotations)\n",
      "    Converts phasor angle into degrees.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    series : pd.Series\n",
      "        The input stream for the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags must contain the unit of the streams, tags are updated with the\n",
      "        new stream units as DEGREES after successful computation.\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations belonging to the stream\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        The output stream following the transformation\n",
      "    \n",
      "    tags : Tags\n",
      "        Tags updated with the new units\n",
      "    \n",
      "    annotations : Annotations\n",
      "        Annotations belonging to the stream\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(degrees)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000   -93.961723\n",
       "2019-09-25 12:00:00.033333100   -94.107292\n",
       "2019-09-25 12:00:00.066666300   -93.530457\n",
       "2019-09-25 12:00:00.100000200   -94.486115\n",
       "2019-09-25 12:00:00.133333200   -94.033226\n",
       "Name: d699e645-09ce-51da-9e16-825d1771cc44, dtype: float64"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = degrees(series, tags, annotations)\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Phasors\n",
    "\n",
    "The phasor transformers operate on a data frame that is composed of two streams - a magnitude and an angle. The order of the streams does not matter so long as the tags and annotations are in the correct order. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fetch_values(*streams, start=START, end=END):\n",
    "    df = pd.concat([\n",
    "        points_to_series(stream.values(start, end), name=str(stream.uuid))\n",
    "        for stream in streams\n",
    "    ], axis=1)\n",
    "    \n",
    "    tags, annotations = [], []\n",
    "    for stream in streams:\n",
    "        tags.append(stream.tags())\n",
    "        annotations.append(stream.annotations()[0])\n",
    "    \n",
    "    return df, tags, annotations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Real"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function real in module conduit.transformers.phasor:\n",
      "\n",
      "real(df, tags, annotations)\n",
      "    Converts the two component streams of a Phasor (Magnitude and Angle) into the\n",
      "    Real part of the Complex Phasor. Handles angles in degrees or radians.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with two columns: one for magnitude and one for angle.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series with the real component of the complex phasor\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units of the magnitude stream\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(real)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    16554.599557\n",
       "2019-09-25 12:00:00.033333100    16523.594812\n",
       "2019-09-25 12:00:00.066666300    16448.274655\n",
       "2019-09-25 12:00:00.100000200    16321.943873\n",
       "2019-09-25 12:00:00.133333200    16324.652888\n",
       "Name: Phasor (Real), dtype: float64"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = real(*fetch_values(vphm, vpha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Imaginary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function imaginary in module conduit.transformers.phasor:\n",
      "\n",
      "imaginary(df, tags, annotations)\n",
      "    Converts the two component streams of a Phasor (Magnitude and Angle) into the\n",
      "    Imaginary part of the Complex Phasor. Handles angles in degrees or radians.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with two columns: one for magnitude and one for angle.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series with the imaginary component of the complex phasor\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units of the magnitude stream\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(imaginary)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000   -65786.456511\n",
       "2019-09-25 12:00:00.033333100   -65836.176858\n",
       "2019-09-25 12:00:00.066666300   -65821.165653\n",
       "2019-09-25 12:00:00.100000200   -65868.220886\n",
       "2019-09-25 12:00:00.133333200   -65889.337612\n",
       "Name: Phasor (Imag), dtype: float64"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = imaginary(*fetch_values(vphm, vpha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Complex Phasor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function complex_phasor in module conduit.transformers.phasor:\n",
      "\n",
      "complex_phasor(df, tags, annotations)\n",
      "    Converts the two component streams of a Phasor (Magnitude and Angle) into a\n",
      "    single complex valued stream. Handles angles in degrees or radians.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with two columns: one for magnitude and one for angle.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series with the complex phasor\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units of the magnitude stream\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(complex_phasor)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    (16554.599557305664-65786.45651093683j)\n",
       "2019-09-25 12:00:00.033333100    (16523.594812107407-65836.17685770646j)\n",
       "2019-09-25 12:00:00.066666300    (16448.274654954985-65821.16565321277j)\n",
       "2019-09-25 12:00:00.100000200     (16321.94387345219-65868.22088606938j)\n",
       "2019-09-25 12:00:00.133333200    (16324.652887704258-65889.33761235172j)\n",
       "Name: Phasor (Complex), dtype: complex128"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = complex_phasor(*fetch_values(vphm, vpha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'distiller': '',\n",
      " 'ingress': 'dfr_72_80',\n",
      " 'name': 'Phasor (Complex)',\n",
      " 'unit': 'VPHM'}\n"
     ]
    }
   ],
   "source": [
    "tags.pprint()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'acronym': {'VPHA', 'VPHM'},\n",
      " 'description': 'Northeast DFR 2 CH 37: Carver 3 Ean',\n",
      " 'devacronym': 'DFR!PMU-NOR2_237',\n",
      " 'enabled': True,\n",
      " 'id': {'24b074cc-20e7-477a-a7a3-8cf02459c487',\n",
      "        '8455c8a7-dc41-4a62-b693-5c50cc2b7198'},\n",
      " 'internal': True,\n",
      " 'label': 'Northeast Carver 3 Ean',\n",
      " 'measurement_type': 'Phasor (Complex)',\n",
      " 'phase': 'A',\n",
      " 'reference': {'DFR!PMU-NOR2_237-PA37', 'DFR!PMU-NOR2_237-PM37'},\n",
      " 'type': 'V'}\n"
     ]
    }
   ],
   "source": [
    "annotations.pprint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Phasor Pairs\n",
    "\n",
    "The phasor pair transformers operate on a data frame that is composed of four streams - both the voltage and the current magnitude and angles. The order of the streams does not matter so long as the tags and annotations are in the correct order. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Complex Power"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function complex_power in module conduit.transformers.phasor:\n",
      "\n",
      "complex_power(df, tags, annotations)\n",
      "    This computes the complex power (P + jQ) in Per Unit or MW+jMVAR based on\n",
      "    the input units.\n",
      "    \n",
      "    Formula: complex_voltage * conj(complex_current)\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with four columns: voltage and current angle and magnitudes.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of complex power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(complex_power)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    (11985909.224562028+3914461.544905271j)\n",
       "2019-09-25 12:00:00.033333100    (11920083.333385102+3918293.133185567j)\n",
       "2019-09-25 12:00:00.066666300     (11836418.09083853+3745856.287387613j)\n",
       "2019-09-25 12:00:00.100000200      (12028983.02103727+4002325.21684728j)\n",
       "2019-09-25 12:00:00.133333200    (11965427.894051684+3875925.331914663j)\n",
       "Name: Complex Power, dtype: complex128"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = complex_power(*fetch_values(vphm, iphm, vpha, ipha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'distiller': '',\n",
      " 'ingress': 'dfr_72_80',\n",
      " 'name': 'Complex Power',\n",
      " 'unit': 'MW + jMVAR'}\n"
     ]
    }
   ],
   "source": [
    "tags.pprint()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'acronym': {'VPHA', 'IPHA', 'VPHM', 'IPHM'},\n",
      " 'description': {'Northeast DFR 2 CH 37: Carver 3 Ean',\n",
      "                 'Northeast DFR 2 CH 40: Carver 3 Ia'},\n",
      " 'devacronym': 'DFR!PMU-NOR2_237',\n",
      " 'enabled': True,\n",
      " 'id': {'24b074cc-20e7-477a-a7a3-8cf02459c487',\n",
      "        '6e76eb5b-a352-4f16-97e7-22ae3b1d9325',\n",
      "        '8455c8a7-dc41-4a62-b693-5c50cc2b7198',\n",
      "        'a4cf92f0-9a7a-4023-8cc5-f1a3f0c22c5a'},\n",
      " 'internal': True,\n",
      " 'label': {'Northeast Carver 3 Ia', 'Northeast Carver 3 Ean'},\n",
      " 'measurement_type': 'Complex Power',\n",
      " 'phase': 'A',\n",
      " 'reference': {'DFR!PMU-NOR2_237-PA37',\n",
      "               'DFR!PMU-NOR2_237-PA40',\n",
      "               'DFR!PMU-NOR2_237-PM37',\n",
      "               'DFR!PMU-NOR2_237-PM40'},\n",
      " 'type': {'V', 'I'}}\n"
     ]
    }
   ],
   "source": [
    "annotations.pprint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Real Power"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function real_power in module conduit.transformers.phasor:\n",
      "\n",
      "real_power(df, tags, annotations)\n",
      "    Computes the real power (P) in Per Unit or MW based on the input units.\n",
      "    \n",
      "    Formula: (complex_voltage * conj(complex_current)).real\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with four columns: voltage and current angle and magnitudes.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of real power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(real_power)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    1.198591e+07\n",
       "2019-09-25 12:00:00.033333100    1.192008e+07\n",
       "2019-09-25 12:00:00.066666300    1.183642e+07\n",
       "2019-09-25 12:00:00.100000200    1.202898e+07\n",
       "2019-09-25 12:00:00.133333200    1.196543e+07\n",
       "Name: Real Power, dtype: float64"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = real_power(*fetch_values(vphm, iphm, vpha, ipha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reactive Power"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function reactive_power in module conduit.transformers.phasor:\n",
      "\n",
      "reactive_power(df, tags, annotations)\n",
      "    This computes the reactive power (Q) in Per Unit or MVAR based on the input units.\n",
      "    \n",
      "    Formula: (complex_voltage * conj(complex_current)).imag\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with four columns: voltage and current angle and magnitudes.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of reactive power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(reactive_power)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    3.914462e+06\n",
       "2019-09-25 12:00:00.033333100    3.918293e+06\n",
       "2019-09-25 12:00:00.066666300    3.745856e+06\n",
       "2019-09-25 12:00:00.100000200    4.002325e+06\n",
       "2019-09-25 12:00:00.133333200    3.875925e+06\n",
       "Name: Reactive Power, dtype: float64"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = reactive_power(*fetch_values(vphm, iphm, vpha, ipha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Apparent Power"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function apparent_power in module conduit.transformers.phasor:\n",
      "\n",
      "apparent_power(df, tags, annotations)\n",
      "    This computes the apparent power (S) in Per Unit or MVA based on the input units.\n",
      "    \n",
      "    Formula: abs(complex_voltage * conj(complex_current))\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with four columns: voltage and current angle and magnitudes.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of apparent power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(apparent_power)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    1.260893e+07\n",
       "2019-09-25 12:00:00.033333100    1.254757e+07\n",
       "2019-09-25 12:00:00.066666300    1.241500e+07\n",
       "2019-09-25 12:00:00.100000200    1.267734e+07\n",
       "2019-09-25 12:00:00.133333200    1.257753e+07\n",
       "Name: Apparent Power, dtype: float64"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = apparent_power(*fetch_values(vphm, iphm, vpha, ipha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Power Factor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function power_factor in module conduit.transformers.phasor:\n",
      "\n",
      "power_factor(df, tags, annotations)\n",
      "    Computes the power factor.\n",
      "    \n",
      "    Formula: real_power() / apparent_power()\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with four columns: voltage and current angle and magnitudes.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of power factor values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(power_factor)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    0.950589\n",
       "2019-09-25 12:00:00.033333100    0.949992\n",
       "2019-09-25 12:00:00.066666300    0.953397\n",
       "2019-09-25 12:00:00.100000200    0.948857\n",
       "2019-09-25 12:00:00.133333200    0.951334\n",
       "Name: Power Factor, dtype: float64"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = power_factor(*fetch_values(vphm, iphm, vpha, ipha))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Phasor Groups\n",
    "\n",
    "The phasor group transformers operate on a data frame that is composed of six streams - magnitude and angles for all three phases of either voltage or current. The order of the streams does not matter so long as the tags and annotations are in the correct order."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "vamag = db.stream_from_uuid(\"11ed9a21-4371-5aa1-8085-b990869d0b51\") # Northeast Carver 3 Ean A VPHM\n",
    "vaang = db.stream_from_uuid(\"8b696776-4a47-54b6-ae3b-4ff6bd218a3f\") # Northeast Carver 3 Ean A VPHA\n",
    "vbmag = db.stream_from_uuid(\"ba69274f-1ddf-5f02-a750-e7b30bc3a0ea\") # Northeast Carver 3 Ebn B VPHM\n",
    "vbang = db.stream_from_uuid(\"a35ecf3e-1d74-5fe0-9894-44cc133c0e38\") # Northeast Carver 3 Ebn B VPHA\n",
    "vcmag = db.stream_from_uuid(\"30866085-71f4-588e-a548-7c58255aaf2f\") # Northeast Carver 3 Ecn C VPHM\n",
    "vcang = db.stream_from_uuid(\"bcf12c7c-8db9-52c3-b03c-3126ed857dbe\") # Northeast Carver 3 Ecn C VPHA\n",
    "\n",
    "iamag = db.stream_from_uuid(\"994c4914-1a7d-51d2-b7cc-8590787dc250\") # Northeast Carver 3 Ia  A IPHM\n",
    "iaang = db.stream_from_uuid(\"d699e645-09ce-51da-9e16-825d1771cc44\") # Northeast Carver 3 Ia  A IPHA\n",
    "ibmag = db.stream_from_uuid(\"d31de3b9-3fa1-50c9-b321-c3fc0d676f36\") # Northeast Carver 3 Ib  B IPHM\n",
    "ibang = db.stream_from_uuid(\"b3dffba0-8fb1-53ef-956a-2de09911c6b4\") # Northeast Carver 3 Ib  B IPHA\n",
    "icmag = db.stream_from_uuid(\"226ed982-55bb-56db-9df0-ad4987eebca4\") # Northeast Carver 3 Ic  C IPHM\n",
    "icang = db.stream_from_uuid(\"70c443f5-3ee0-5e44-a72e-d9898b002114\") # Northeast Carver 3 Ic  C IPHA"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Complex Phasor Group"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function complex_phasor_group in module conduit.transformers.phasor:\n",
      "\n",
      "complex_phasor_group(df, tags, annotations)\n",
      "    Returns the phasor group as complex phasors for each power phase.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with six columns: angle and magnitudes for three phases.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    data : pd.DataFrame\n",
      "        A DataFrame with a complex phasor for each power phase\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        Tags describing each column (power phase) in the output\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        Annotations describing each column (power phase) in the output\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(complex_phasor_group)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "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>Phase A</th>\n",
       "      <th>Phase B</th>\n",
       "      <th>Phase C</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.000000000</th>\n",
       "      <td>(16554.599557305664-65786.45651093683j)</td>\n",
       "      <td>(-65549.85809076928+18478.529450977243j)</td>\n",
       "      <td>(48961.09892911847+47339.69245258796j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.033333100</th>\n",
       "      <td>(16523.594812107407-65836.17685770646j)</td>\n",
       "      <td>(-65542.07656572085+18538.83153070996j)</td>\n",
       "      <td>(48976.035527156295+47341.57447823345j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.066666300</th>\n",
       "      <td>(16448.274654954985-65821.16565321277j)</td>\n",
       "      <td>(-65517.785694548795+18568.015351667025j)</td>\n",
       "      <td>(49043.13305288382+47283.037157749306j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.100000200</th>\n",
       "      <td>(16321.94387345219-65868.22088606938j)</td>\n",
       "      <td>(-65490.0252807664+18650.037252234473j)</td>\n",
       "      <td>(49099.46017793011+47243.04700471929j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.133333200</th>\n",
       "      <td>(16324.652887704258-65889.33761235172j)</td>\n",
       "      <td>(-65463.963648283694+18759.98081494591j)</td>\n",
       "      <td>(49085.63863773546+47154.38227058879j)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                               Phase A  \\\n",
       "2019-09-25 12:00:00.000000000  (16554.599557305664-65786.45651093683j)   \n",
       "2019-09-25 12:00:00.033333100  (16523.594812107407-65836.17685770646j)   \n",
       "2019-09-25 12:00:00.066666300  (16448.274654954985-65821.16565321277j)   \n",
       "2019-09-25 12:00:00.100000200   (16321.94387345219-65868.22088606938j)   \n",
       "2019-09-25 12:00:00.133333200  (16324.652887704258-65889.33761235172j)   \n",
       "\n",
       "                                                                 Phase B  \\\n",
       "2019-09-25 12:00:00.000000000   (-65549.85809076928+18478.529450977243j)   \n",
       "2019-09-25 12:00:00.033333100    (-65542.07656572085+18538.83153070996j)   \n",
       "2019-09-25 12:00:00.066666300  (-65517.785694548795+18568.015351667025j)   \n",
       "2019-09-25 12:00:00.100000200    (-65490.0252807664+18650.037252234473j)   \n",
       "2019-09-25 12:00:00.133333200   (-65463.963648283694+18759.98081494591j)   \n",
       "\n",
       "                                                               Phase C  \n",
       "2019-09-25 12:00:00.000000000   (48961.09892911847+47339.69245258796j)  \n",
       "2019-09-25 12:00:00.033333100  (48976.035527156295+47341.57447823345j)  \n",
       "2019-09-25 12:00:00.066666300  (49043.13305288382+47283.037157749306j)  \n",
       "2019-09-25 12:00:00.100000200   (49099.46017793011+47243.04700471929j)  \n",
       "2019-09-25 12:00:00.133333200   (49085.63863773546+47154.38227058879j)  "
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df, tags, annotations = complex_phasor_group(*fetch_values(vamag, vbmag, vcmag, vaang, vbang, vcang))\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'distiller': '', 'ingress': 'dfr_72_80', 'name': 'Phase A', 'unit': 'VPHM'},\n",
      " {'distiller': '', 'ingress': 'dfr_72_80', 'name': 'Phase B', 'unit': 'VPHM'},\n",
      " {'distiller': '', 'ingress': 'dfr_72_80', 'name': 'Phase C', 'unit': 'VPHM'}]\n"
     ]
    }
   ],
   "source": [
    "tags.pprint()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'acronym': {'VPHA', 'VPHM'},\n",
      "  'description': 'Northeast DFR 2 CH 37: Carver 3 Ean',\n",
      "  'devacronym': 'DFR!PMU-NOR2_237',\n",
      "  'enabled': True,\n",
      "  'id': {'24b074cc-20e7-477a-a7a3-8cf02459c487',\n",
      "         '8455c8a7-dc41-4a62-b693-5c50cc2b7198'},\n",
      "  'internal': True,\n",
      "  'label': 'Northeast Carver 3 Ean',\n",
      "  'measurement_type': 'Phasor (Complex)',\n",
      "  'phase': 'A',\n",
      "  'reference': {'DFR!PMU-NOR2_237-PA37', 'DFR!PMU-NOR2_237-PM37'},\n",
      "  'type': 'V'},\n",
      " {'acronym': {'VPHA', 'VPHM'},\n",
      "  'description': 'Northeast DFR 2 CH 38: Carver 3 Ebn',\n",
      "  'devacronym': 'DFR!PMU-NOR2_237',\n",
      "  'enabled': True,\n",
      "  'id': {'8d0ac3a5-0077-42ab-81d0-1b7f600bb2e1',\n",
      "         'ecd9e83b-76b4-4a62-9007-5d46e56fa388'},\n",
      "  'internal': True,\n",
      "  'label': 'Northeast Carver 3 Ebn',\n",
      "  'measurement_type': 'Phasor (Complex)',\n",
      "  'phase': 'B',\n",
      "  'reference': {'DFR!PMU-NOR2_237-PA38', 'DFR!PMU-NOR2_237-PM38'},\n",
      "  'type': 'V'},\n",
      " {'acronym': {'VPHA', 'VPHM'},\n",
      "  'description': 'Northeast DFR 2 CH 39: Carver 3 Ecn',\n",
      "  'devacronym': 'DFR!PMU-NOR2_237',\n",
      "  'enabled': True,\n",
      "  'id': {'b103ea79-2106-4ae9-a39c-5966e5b72a61',\n",
      "         'f5c2afb8-f10b-4ebf-aa85-8ed44784aada'},\n",
      "  'internal': True,\n",
      "  'label': 'Northeast Carver 3 Ecn',\n",
      "  'measurement_type': 'Phasor (Complex)',\n",
      "  'phase': 'C',\n",
      "  'reference': {'DFR!PMU-NOR2_237-PM39', 'DFR!PMU-NOR2_237-PA39'},\n",
      "  'type': 'V'}]\n"
     ]
    }
   ],
   "source": [
    "annotations.pprint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Sequence Components"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function sequence_components in module conduit.transformers.phasor:\n",
      "\n",
      "sequence_components(df, tags, annotations)\n",
      "    Formula is here: https://en.wikipedia.org/wiki/Symmetrical_components\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with six columns: angle and magnitudes for three phases.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    data : pd.DataFrame\n",
      "        A DataFrame with all three sequence components over time\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        Tags describing each column (sequence component) in the output\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        Annotations describing each column (sequence component) in the output\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(sequence_components)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "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>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.000000000</th>\n",
       "      <td>(-11.386534781716666+10.588464209458227j)</td>\n",
       "      <td>(16614.493160096477-65954.98841787007j)</td>\n",
       "      <td>(-48.50706800910848+157.94344272378294j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.033333100</th>\n",
       "      <td>(-14.148742152385239+14.743050412313702j)</td>\n",
       "      <td>(16583.507474206017-65983.99137601457j)</td>\n",
       "      <td>(-45.76391994623797+133.07146789578715j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.066666300</th>\n",
       "      <td>(-8.792662236662483+9.96228540118803j)</td>\n",
       "      <td>(16517.846443359595-65986.45260802751j)</td>\n",
       "      <td>(-60.779126167957045+155.32466941355352j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.100000200</th>\n",
       "      <td>(-22.873743128033915+8.287790294792405j)</td>\n",
       "      <td>(16426.499747059443-66017.38947612165j)</td>\n",
       "      <td>(-81.682130479232+140.8807997574792j)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-09-25 12:00:00.133333200</th>\n",
       "      <td>(-17.890707614659426+8.341824394325764j)</td>\n",
       "      <td>(16368.029459606303-66016.46157607189j)</td>\n",
       "      <td>(-25.485864287390235+118.78213932583822j)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                                       0  \\\n",
       "2019-09-25 12:00:00.000000000  (-11.386534781716666+10.588464209458227j)   \n",
       "2019-09-25 12:00:00.033333100  (-14.148742152385239+14.743050412313702j)   \n",
       "2019-09-25 12:00:00.066666300     (-8.792662236662483+9.96228540118803j)   \n",
       "2019-09-25 12:00:00.100000200   (-22.873743128033915+8.287790294792405j)   \n",
       "2019-09-25 12:00:00.133333200   (-17.890707614659426+8.341824394325764j)   \n",
       "\n",
       "                                                                     1  \\\n",
       "2019-09-25 12:00:00.000000000  (16614.493160096477-65954.98841787007j)   \n",
       "2019-09-25 12:00:00.033333100  (16583.507474206017-65983.99137601457j)   \n",
       "2019-09-25 12:00:00.066666300  (16517.846443359595-65986.45260802751j)   \n",
       "2019-09-25 12:00:00.100000200  (16426.499747059443-66017.38947612165j)   \n",
       "2019-09-25 12:00:00.133333200  (16368.029459606303-66016.46157607189j)   \n",
       "\n",
       "                                                                       2  \n",
       "2019-09-25 12:00:00.000000000   (-48.50706800910848+157.94344272378294j)  \n",
       "2019-09-25 12:00:00.033333100   (-45.76391994623797+133.07146789578715j)  \n",
       "2019-09-25 12:00:00.066666300  (-60.779126167957045+155.32466941355352j)  \n",
       "2019-09-25 12:00:00.100000200      (-81.682130479232+140.8807997574792j)  \n",
       "2019-09-25 12:00:00.133333200  (-25.485864287390235+118.78213932583822j)  "
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df, tags, annotations = sequence_components(*fetch_values(vamag, vbmag, vcmag, vaang, vbang, vcang))\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Zero Sequence"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function zero_sequence in module conduit.transformers.phasor:\n",
      "\n",
      "zero_sequence(df, tags, annotations)\n",
      "    Formula is (A + B + C) / 3.\n",
      "    This is phasor math in complex plane.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with six columns: angle and magnitudes for three phases.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of the complex zero sequence component over time.\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(zero_sequence)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000      (2.23949310621893+2.6462203519525738j)\n",
       "2019-09-25 12:00:00.033333100     (1.5695822672592876+3.684455236186873j)\n",
       "2019-09-25 12:00:00.066666300    (2.1526488740688023+3.4309302394670214j)\n",
       "2019-09-25 12:00:00.100000200     (1.7474029518463965+2.557173334397087j)\n",
       "2019-09-25 12:00:00.133333200     (1.911485538275182+2.6919245012804867j)\n",
       "Name: 0, dtype: complex128"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = zero_sequence(*fetch_values(iamag, ibmag, icmag, iaang, ibang, icang))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Positive Sequence"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function positive_sequence in module conduit.transformers.phasor:\n",
      "\n",
      "positive_sequence(df, tags, annotations)\n",
      "    Formula is (A + B * 1<120 + C * 1<240) / 3\n",
      "    ALPHA and ALPHA_2 are unit vectors at 120 degrees and -120 degrees, respectively.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with six columns: angle and magnitudes for three phases.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of the complex positive sequence component over time.\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(positive_sequence)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    (-16.403419329825557-180.23570452358334j)\n",
       "2019-09-25 12:00:00.033333100      (-16.20830021993057-180.9226513069945j)\n",
       "2019-09-25 12:00:00.066666300    (-15.565139615876918-179.44080903244947j)\n",
       "2019-09-25 12:00:00.100000200    (-17.485074351805768-181.04938818482356j)\n",
       "2019-09-25 12:00:00.133333200     (-16.227252795516353-179.4508411644463j)\n",
       "Name: 1, dtype: complex128"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = positive_sequence(*fetch_values(iamag, ibmag, icmag, iaang, ibang, icang))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Negative Sequence"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function negative_sequence in module conduit.transformers.phasor:\n",
      "\n",
      "negative_sequence(df, tags, annotations)\n",
      "    Formula is (A + B * 1<240 + C * 1<120) / 3\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with six columns: angle and magnitudes for three phases.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of the complex negative sequence component over time.\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(negative_sequence)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    (1.3221729271500255-7.836209123927849j)\n",
       "2019-09-25 12:00:00.033333100    (1.3986265249328274-7.141544958935862j)\n",
       "2019-09-25 12:00:00.066666300     (2.144124093195633-6.632940748163965j)\n",
       "2019-09-25 12:00:00.100000200    (1.1254583483192278-7.750598107157808j)\n",
       "2019-09-25 12:00:00.133333200     (1.2836468938047574-8.06875313408868j)\n",
       "Name: 2, dtype: complex128"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = negative_sequence(*fetch_values(iamag, ibmag, icmag, iaang, ibang, icang))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Phasor Group Pairs\n",
    "\n",
    "The phasor group pair transformers operate on a data frame that is composed of 12 streams - magnitude and angles for all three phases of both voltage and current. The order of the streams does not matter so long as the tags and annotations are in the correct order."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Three Phase Complex Power"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function three_phase_complex_power in module conduit.transformers.phasor:\n",
      "\n",
      "three_phase_complex_power(df, tags, annotations)\n",
      "    Computes the complex power (P + jQ) summed across all three phases.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with 12 columns: voltage and current angles and magnitudes for\n",
      "        three phases, A, B, and C.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of three phase complex power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(three_phase_complex_power)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000     (34840830.03853895+12228884.319036357j)\n",
       "2019-09-25 12:00:00.033333100     (35004677.89714943+12209265.135494957j)\n",
       "2019-09-25 12:00:00.066666300     (34747243.59058613+11973136.740621518j)\n",
       "2019-09-25 12:00:00.100000200    (34991960.364504814+12383775.411200736j)\n",
       "2019-09-25 12:00:00.133333200    (34740295.583532214+12025600.218836717j)\n",
       "dtype: complex128"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = three_phase_complex_power(*fetch_values(\n",
    "    vamag, iamag, vbmag, ibmag, vcmag, icmag, vaang, iaang, vbang, ibang, vcang, icang\n",
    "))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'distiller': '',\n",
      " 'ingress': 'dfr_72_80',\n",
      " 'name': 'Complex Power',\n",
      " 'unit': 'MW + jMVAR'}\n"
     ]
    }
   ],
   "source": [
    "tags.pprint()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'acronym': {'VPHA', 'IPHA', 'VPHM', 'IPHM'},\n",
      " 'description': set(),\n",
      " 'devacronym': 'DFR!PMU-NOR2_237',\n",
      " 'enabled': True,\n",
      " 'id': set(),\n",
      " 'internal': True,\n",
      " 'label': set(),\n",
      " 'measurement_type': 'Complex Power',\n",
      " 'phase': {'A', 'B', 'C'},\n",
      " 'reference': set(),\n",
      " 'type': {'V', 'I'}}\n"
     ]
    }
   ],
   "source": [
    "annotations.pprint()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Three Phase MW"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function three_phase_mw in module conduit.transformers.phasor:\n",
      "\n",
      "three_phase_mw(df, tags, annotations)\n",
      "    Computes the real power (P) summed across all three phases.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with 12 columns: voltage and current angles and magnitudes for\n",
      "        three phases, A, B, and C.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of three phase real power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(three_phase_mw)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    3.484083e+07\n",
       "2019-09-25 12:00:00.033333100    3.500468e+07\n",
       "2019-09-25 12:00:00.066666300    3.474724e+07\n",
       "2019-09-25 12:00:00.100000200    3.499196e+07\n",
       "2019-09-25 12:00:00.133333200    3.474030e+07\n",
       "dtype: float64"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = three_phase_mw(*fetch_values(\n",
    "    vamag, iamag, vbmag, ibmag, vcmag, icmag, vaang, iaang, vbang, ibang, vcang, icang\n",
    "))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Three Phase MVAR"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function three_phase_mvar in module conduit.transformers.phasor:\n",
      "\n",
      "three_phase_mvar(df, tags, annotations)\n",
      "    Computes the reactive power (Q) summed across all three phases.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with 12 columns: voltage and current angles and magnitudes for\n",
      "        three phases, A, B, and C.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of three phase reactive power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(three_phase_mvar)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    1.222888e+07\n",
       "2019-09-25 12:00:00.033333100    1.220927e+07\n",
       "2019-09-25 12:00:00.066666300    1.197314e+07\n",
       "2019-09-25 12:00:00.100000200    1.238378e+07\n",
       "2019-09-25 12:00:00.133333200    1.202560e+07\n",
       "dtype: float64"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = three_phase_mvar(*fetch_values(\n",
    "    vamag, iamag, vbmag, ibmag, vcmag, icmag, vaang, iaang, vbang, ibang, vcang, icang\n",
    "))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Three Phase MVA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function three_phase_mva in module conduit.transformers.phasor:\n",
      "\n",
      "three_phase_mva(df, tags, annotations)\n",
      "    Computes the apparent power (S) summed across all three phases.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with 12 columns: voltage and current angles and magnitudes for\n",
      "        three phases, A, B, and C.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of three phase apparent power values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(three_phase_mva)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    3.696332e+07\n",
       "2019-09-25 12:00:00.033333100    3.711091e+07\n",
       "2019-09-25 12:00:00.066666300    3.678926e+07\n",
       "2019-09-25 12:00:00.100000200    3.715465e+07\n",
       "2019-09-25 12:00:00.133333200    3.680171e+07\n",
       "dtype: float64"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = three_phase_mva(*fetch_values(\n",
    "    vamag, iamag, vbmag, ibmag, vcmag, icmag, vaang, iaang, vbang, ibang, vcang, icang\n",
    "))\n",
    "series.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Three Phase Power Factor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function three_phase_power_factor in module conduit.transformers.phasor:\n",
      "\n",
      "three_phase_power_factor(df, tags, annotations)\n",
      "    Computes the power factor summed across all three phases.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    df : pd.DataFrame\n",
      "        The input data with 12 columns: voltage and current angles and magnitudes for\n",
      "        three phases, A, B, and C.\n",
      "    \n",
      "    tags : TagsGroup\n",
      "        A collection of tags that describe each column in the input data.\n",
      "    \n",
      "    annotations : AnnotationsGroup\n",
      "        A collection of annotations that describe each column in the input data.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    series : pd.Series\n",
      "        A single series of three phase power factor values over time\n",
      "    \n",
      "    tags : Tags\n",
      "        A single tagset with the units based on the input\n",
      "    \n",
      "    annotations : Annotations\n",
      "        A single annotationset with the new stream type\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(three_phase_power_factor)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2019-09-25 12:00:00.000000000    2.827479\n",
       "2019-09-25 12:00:00.033333100    2.829742\n",
       "2019-09-25 12:00:00.066666300    2.833472\n",
       "2019-09-25 12:00:00.100000200    2.825192\n",
       "2019-09-25 12:00:00.133333200    2.831764\n",
       "dtype: float64"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series, tags, annotations = three_phase_power_factor(*fetch_values(\n",
    "    vamag, iamag, vbmag, ibmag, vcmag, icmag, vaang, iaang, vbang, ibang, vcang, icang\n",
    "))\n",
    "series.head()"
   ]
  }
 ],
 "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.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
