{ "cells": [ { "cell_type": "markdown", "id": "6d747389", "metadata": {}, "source": [ "# Time dependent data / Welding current and voltage\n", "\n", "[<< PREVIOUS TUTORIAL](01_01_introduction.ipynb) | [NEXT TUTORIAL >>](01_03_geometry.ipynb)\n", "\n", "## Overview\n", "\n", "**This tutorial covers:**\n", "\n", "- Accessing and visualizing time dependent data stored inside a `TimeSeries` class\n", "\n", "**Requirements:**\n", "\n", "- Opening and navigating through WelDX files ([tutorial](01_01_introduction.ipynb))" ] }, { "cell_type": "code", "execution_count": null, "id": "edeb5c02", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false }, "nbsphinx": "hidden", "tags": [] }, "outputs": [], "source": [ "# download the example file for this tutorial\n", "\n", "from util import download_tutorial_input_file\n", "\n", "download_tutorial_input_file(print_status=False)" ] }, { "cell_type": "markdown", "id": "1cfb7522", "metadata": { "tags": [] }, "source": [ "## Plotting data\n", "\n", "\n", "Two important quantities in welding applications are the welding current and welding voltage.\n", "Both are constantly monitored during an experiment.\n", "The obtained data is a one dimensional array with time being its only dimension.\n", "We will extract both from the file and see what we can do with it.\n", "First we read the file and get an overview over its content as we learned in the previous tutorial:" ] }, { "cell_type": "code", "execution_count": null, "id": "a1f650a0", "metadata": {}, "outputs": [], "source": [ "from weldx import WeldxFile\n", "\n", "wxfile = WeldxFile(\"single_pass_weld.wx\")" ] }, { "cell_type": "code", "execution_count": null, "id": "ea678360", "metadata": {}, "outputs": [], "source": [ "wxfile.info()" ] }, { "cell_type": "markdown", "id": "a529651a", "metadata": {}, "source": [ "As we can see in the list, there are the top level items `welding_current` and `welding_voltage`.\n", "Let's have a look at the welding current first:" ] }, { "cell_type": "code", "execution_count": null, "id": "1af19636", "metadata": {}, "outputs": [], "source": [ "current = wxfile[\"welding_current\"]" ] }, { "cell_type": "markdown", "id": "0d0e04ec", "metadata": {}, "source": [ "The object we extracted is of type `TimeSeries` as can be seen in the `info` output.\n", "This is a special type provided by WelDX to deal with time dependent data.\n", "\n", "To see a plot of the `TimeSeries` simply call the built-in `.plot()` function.\n", "If you are already familiar with `matplotlib` it is also easy to generate your own plots. We show how to access the underlying data later in this tutorial.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "f32813e6", "metadata": {}, "outputs": [], "source": [ "current.plot()" ] }, { "cell_type": "markdown", "id": "f45b4d28", "metadata": {}, "source": [ "The `plot` method is an easy and convenient way to quickly visualize a `TimeSeries`.\n", "It labels the axes automatically and attaches the corresponding units to them.\n", "\n", "Depending on the Python environment you are using, there are some things to consider.\n", "Since the `plot` method uses `matplotlib` internally, you have to call the `matplotlib.pyplot.show` function manually after using `plot` when running a regular Python script file.\n", "Otherwise, the plot won't show up.\n", "\n", "This is not the case if you work with a jupyter notebook, where the plots are generated after each cell execution.\n", "However, while a regular script will open an interactive window for each plot, the plots inside a notebook can't be modified without additional commands.\n", "To enable interactive `matplotlib` plots inside a jupyter notebook, uncomment and run the following magic command:" ] }, { "cell_type": "code", "execution_count": null, "id": "d00a332f", "metadata": {}, "outputs": [], "source": [ "# %matplotlib widget" ] }, { "cell_type": "markdown", "id": "26aa4691", "metadata": {}, "source": [ "Now let's plot the welding voltage. \n", "Try to interact with the plot if you are running this tutorial as a jupyter notebook.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "ca2ce187", "metadata": {}, "outputs": [], "source": [ "voltage = wxfile[\"welding_voltage\"]\n", "voltage.plot()" ] }, { "cell_type": "markdown", "id": "19eb4fdc", "metadata": {}, "source": [ "## Accessing the data \n", "\n", "Now that we know how to get a quick overview over the data by visualizing it with the `plot` method, let's have a look on what else we can do with a `TimeSeries`.\n", "While any number of dimensions in addition to time are supported, we expect the welding current to have no further dimensions.\n", "We can easily check this using the `shape` property:" ] }, { "cell_type": "code", "execution_count": null, "id": "4a72e1a2", "metadata": {}, "outputs": [], "source": [ "current.shape" ] }, { "cell_type": "markdown", "id": "ac8e05a3", "metadata": {}, "source": [ "From the returned value we see that the data indeed only consists of a single dimension.\n", "Furthermore, we get the exact number of data points that are stored in the time series.\n", "\n", "We already saw in the axes labeling of the plots, that the `TimeSeries` also stores the units of the data \n", "We can get it by calling the `units` property:" ] }, { "cell_type": "code", "execution_count": null, "id": "e4a4c1a8", "metadata": {}, "outputs": [], "source": [ "current.units" ] }, { "cell_type": "markdown", "id": "b8bdbd95", "metadata": {}, "source": [ "As one might expect, the unit of the current is amperes, but it might also have been stored in milliamperes.\n", "\n", "Now, if we want to actually access the stored data, we can extract it from the `TimeSeries` by using its `data` property.\n", "The returned object is a `pint.Quantity`.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "22934d29", "metadata": {}, "outputs": [], "source": [ "type(current.data)" ] }, { "cell_type": "markdown", "id": "fb036ded", "metadata": {}, "source": [ "A `pint.Quantity` is a thin wrapper around a multi-dimensional array that attaches units to the contained data.\n", "They can be used like NumPy arrays and support most of NumPy's functions.\n", "For further information on how to work with quantities, consult [Pint's documentation](https://pint.readthedocs.io/en/stable/).\n", "\n", "An alternative to the `data` property is the `data_array` property.\n", "This returns the data as `xarray.DataArray`:" ] }, { "cell_type": "code", "execution_count": null, "id": "aab663a7", "metadata": {}, "outputs": [], "source": [ "type(current.data_array)" ] }, { "cell_type": "markdown", "id": "5e09e9b4", "metadata": {}, "source": [ "Xarray is a powerful tool that makes working with multi-dimensional arrays easier.\n", "When performing operations on an `xarray.DataArray`, it automatically figures out which dimensions of the operands are compatible with each other and how they need to be combined.\n", "Visit [the xarray documentation](http://xarray.pydata.org/en/stable/) to learn how to work with xarray classes.\n", "\n", "We recommend using either xarray or pint when working with the data, but if you feel more comfortable using NumPy, you can convert both types easily to a `numpy.ndarray`.\n", "For pint use `.magnitude` or the short version `.m`:" ] }, { "cell_type": "code", "execution_count": null, "id": "dc20a262", "metadata": {}, "outputs": [], "source": [ "type(current.data.magnitude)" ] }, { "cell_type": "markdown", "id": "fcb79231", "metadata": {}, "source": [ "For xarray use `.data` to get the data as `pint.Quantity` and then `.magnitude` or `.m` to receive a `numpy.ndarray`:" ] }, { "cell_type": "code", "execution_count": null, "id": "73cacaae", "metadata": {}, "outputs": [], "source": [ "type(current.data_array.data.magnitude)" ] }, { "cell_type": "markdown", "id": "e25735b8", "metadata": {}, "source": [ "## Data processing examples\n", "\n", "Before we conclude this lesson, we will show you some simple examples on how to process the data obtained from a weldx file.\n", "Pint and Xarray both offer you some basic functions to get the minimal and maximal values of a dataset or to calculate its mean value.\n", "Here are the examples for Pint:" ] }, { "cell_type": "code", "execution_count": null, "id": "9c2a36f3", "metadata": {}, "outputs": [], "source": [ "current.data.min()" ] }, { "cell_type": "code", "execution_count": null, "id": "b28100f2", "metadata": {}, "outputs": [], "source": [ "current.data.max()" ] }, { "cell_type": "code", "execution_count": null, "id": "ca769f05", "metadata": {}, "outputs": [], "source": [ "current.data.mean()" ] }, { "cell_type": "markdown", "id": "43f99b83", "metadata": {}, "source": [ "If you exchange `.data` with `.data_array`, you will get the same results just as `xarray.DataArray`.\n", "\n", "To demonstrate you some features of Xarray and Pint, we will now do a more involved computation by calculating the electric power using the equation:\n", "\n", "$$ P = \\frac{1}{T} \\int_{t=0}^{T} u \\cdot i \\;\\mathrm{d} t$$\n", "\n", "$u$ is the time dependent current, $i$ the time dependent voltage, $t$ the time and $T$ the duration of the measurement.\n", "We will do this step by step to keep it simple and to discuss all the things that need to be considered.\n", "First we will calculate the integral with [Xarrays `.integrate` function](http://xarray.pydata.org/en/stable/generated/xarray.DataArray.integrate.html) which uses the trapezoidal rule." ] }, { "cell_type": "code", "execution_count": null, "id": "5972af2b", "metadata": {}, "outputs": [], "source": [ "integral = (voltage.data_array * current.data_array).integrate(\n", " \"time\", datetime_unit=\"s\"\n", ")\n", "integral" ] }, { "cell_type": "markdown", "id": "9cb722fd", "metadata": {}, "source": [ "The parameter `datetime_unit` specifies the unit of the time coordinates during the integration.\n", "Unfortunately, at the time of writing of this tutorial, the unit support of Xarray is still work in progress and not fully implemented.\n", "The result's unit is just $\\mathrm{A \\cdot V}$ while it should have been $\\mathrm{A \\cdot V \\cdot s}$.\n", "We correct this by turning the resulting `xarray.DataArray` into a `pint.Quantity` (see previous section) and simply multiplying the missing unit.\n", "Therefore we need to import the unit object `U_` from weldx." ] }, { "cell_type": "code", "execution_count": null, "id": "f4de64ae", "metadata": {}, "outputs": [], "source": [ "from weldx import U_\n", "\n", "q_integral = integral.data * U_(\"s\")" ] }, { "cell_type": "markdown", "id": "eb8f4d78", "metadata": {}, "source": [ "What remains now is to divide the result by the process duration.\n", "We can get the time data either from the voltage or the current data as they were both measured simultaneously.\n", "It can be accessed with `.time` which returns a `weldx.Time` instance.\n", "We will talk a bit more about this class in another tutorial.\n", "For now it is sufficient to know, that it provides a `.duration` method to get the duration of the contained time data as a new `weldx.Time` instance and that we can turn it into a quantity using `.as_quantity`.\n", "So let's finally calculate the electrical power:" ] }, { "cell_type": "code", "execution_count": null, "id": "612ac8a3", "metadata": {}, "outputs": [], "source": [ "e_power = q_integral / voltage.time.duration.as_quantity()\n", "e_power" ] }, { "cell_type": "markdown", "id": "faeb7055", "metadata": {}, "source": [ "We can further simplify this by convert the units manually to Watt with `.to` or `.ito`.\n", "The first method creates a new quantity, while the latter one modifies the existing one." ] }, { "cell_type": "code", "execution_count": null, "id": "05f66239", "metadata": {}, "outputs": [], "source": [ "e_power.ito(\"W\")\n", "e_power" ] }, { "cell_type": "markdown", "id": "3f41c72f", "metadata": {}, "source": [ "If you prefer compact numbers, you can use `.to_compact`:" ] }, { "cell_type": "code", "execution_count": null, "id": "4d6dadbe", "metadata": {}, "outputs": [], "source": [ "e_power.to_compact()" ] }, { "cell_type": "markdown", "id": "a6b8cbec", "metadata": {}, "source": [ "## Conclusion\n", "\n", "This concludes the tutorial about accessing and plotting time dependent data.\n", "We have learned about some basic functionalities of the `TimeSeries` class and know now, how to get the data for further processing and how to quickly visualize it, using the `plot` method.\n", "\n", "## Further readings\n", "\n", "- [API tutorial: TimeSeries](timeseries_01.ipynb)\n", "\n", "[<< PREVIOUS TUTORIAL](01_01_introduction.ipynb) | [NEXT TUTORIAL >>](01_03_geometry.ipynb)" ] } ], "metadata": { "kernelspec": { "display_name": "", "language": "python", "name": "" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.12" } }, "nbformat": 4, "nbformat_minor": 5 }