{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "## LG M50 Single Pulse Parameter Identification\n", "\n", "This example presents an experimental parameter identification method for a two-RC circuit model. The data for this notebook is located within the same directory and was obtained from WDWidanage/Simscape-Battery-Library [[1]](https://github.com/WDWidanage/Simscape-Battery-Library/tree/a3842b91b3ccda006bc9be5d59c8bcbd167ceef7/Examples/parameterEstimation_TECMD/Data).\n", "\n", "\n", "### Setting up the Environment\n", "\n", "Before we begin, we need to ensure that we have all the necessary tools. We will install PyBOP for the fitting and Pandas for the data ingestion and manipulation:" ] }, { "cell_type": "code", "execution_count": null, "id": "1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/home/engs2510/Documents/Git/PyBOP/.nox/notebooks-overwrite/bin/python3: No module named pip\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Note: you may need to restart the kernel to use updated packages.\n", "zsh:1: no matches found: pybop[plot]\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Note: you may need to restart the kernel to use updated packages.\n", "/home/engs2510/Documents/Git/PyBOP/.nox/notebooks-overwrite/bin/python3: No module named pip" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "%pip install --upgrade pip ipywidgets -q\n", "%pip install pybop[plot] -q\n", "%pip install pandas -q" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "### Importing Libraries\n", "\n", "With the environment set up, we can now import PyBOP alongside other libraries we will need:" ] }, { "cell_type": "code", "execution_count": null, "id": "3", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "import pybamm\n", "from scipy.io import loadmat\n", "\n", "import pybop\n", "\n", "go = pybop.PlotlyManager().go\n", "pybop.PlotlyManager().pio.renderers.default = \"notebook_connected\"" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "Let's fix the random seed in order to generate consistent output during development, although this does not need to be done in practice." ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "np.random.seed(8)" ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "## Importing Data\n", "\n", "The data is imported as a dictionary with the following key level:\n", "- [\"LGM50_5Ah_Pulse\"]\n", " - Temperature-> [\"T0\"]\n", " - State of Charge ->[\"SoC3\"]\n", " - Cell number -> [\"Cell1\"]\n", " - Corresponding data -> [\"data\"]\n", "\n", "Using SciPy's `loadmat`, we import the data from the MAT containers:" ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "ocp = loadmat(\n", " \"../data/LG_M50_ECM/data/LGM50_5Ah_OCV.mat\", simplify_cells=True, mat_dtype=False\n", ")\n", "pulse_data = loadmat(\n", " \"../data/LG_M50_ECM/data/LGM50_5Ah_Pulse.mat\", simplify_cells=True, mat_dtype=False\n", ")\n", "rate_data = loadmat(\n", " \"../data/LG_M50_ECM/data/LGM50_5Ah_RateTest.mat\",\n", " simplify_cells=True,\n", " mat_dtype=False,\n", ")" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "### Convert to Dataframes\n", "\n", "Next, we construct a dataframe from a selected pulse. In this case, we select the data for zero degrees (`T0`) with a state-of-charge of 90% (`SoC9`) and the 19th cell (`Cell19`). This can be extended to multiple pulses, or a different selection.\n", "\n", "Additionally, we apply two filters to the dataframe to ensure the data contains only monotonically increasing time samples without duplicates." ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "df = pd.DataFrame(pulse_data[\"LGM50_5Ah_Pulse\"][\"T0\"][\"SoC9\"][\"Cell19\"][\"data\"])\n", "df[\"ProgTime\"] = df[\"ProgTime\"] - df[\"ProgTime\"].min()\n", "df.drop_duplicates(subset=[\"ProgTime\"], inplace=True)" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "A plot of time vs voltage confirms the data looks correct for fitting. In this situation, we would prefer to have additional samples from the relaxation, but as we will show below, PyBOP is still able to identify parameter values that fit this system." ] }, { "cell_type": "code", "execution_count": null, "id": "11", "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "