{ "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 }