Dynamic analysis II¶
In this example we simulate different SOC breakpoints for the baseline and virtual cell with 5% less NPratio, and compare the capacity and DCIR.
from breathe_design import api_interface as api
from breathe_design import Cycler
from breathe_design import enable_notebook_plotly
import plotly.express as px
enable_notebook_plotly()
As before, we first import the necessary modules and define the base battery, cycler, and designs.
base_params = api.get_design_parameters("Molicel P45B")
eqm_results = api.get_eqm_kpis("Molicel P45B")
designs = [{"designName": "Lower NP", "NPratio": base_params["NPratio"] * 0.95}]
baseline_capacity = eqm_results.capacity
cycler = Cycler(selected_unit="C", cell_capacity=baseline_capacity)
We can pass a list of SOC breakpoints to the initialSoC parameter of the run_sim function to simulate different SOCs.
# define some SOC breakpoints we want to simulate
soc_bps = [0.25, 0.5, 0.75]
# run a batch of simulations for different SOC breakpoints
output = api.run_sim(
base_battery="Molicel P45B",
cycler=cycler.cc_chg(1.0, 4.2),
designs=designs,
initialSoC=soc_bps,
initialTemperature_degC=21.0,
)
Running...: 0%| | 0/1 [00:00<?, ? designs/s] Running...: 100%|██████████| 1/1 [00:06<00:00, 6.67s/ designs] Running...: 100%|██████████| 1/1 [00:17<00:00, 17.84s/ designs] Running...: 100%|██████████| 1/1 [00:18<00:00, 18.11s/ designs]
The dynamic output data is now returned as a list of dictionaries, where each dictionary contains the simulation results for a given SOC breakpoint.
output.plot_voltage_response()
Let's also take this a step further and run a DCIR test. Here we can define different arguments that can be tailored to your specific requirements.
cycler_dict = cycler.dcir(
I_app=-1.0, t_dur=60.0, t_rest_before=3.0, t_rest_after=200.0, V_min=2.5, V_max=4.2
)
We will also define the initial voltage instead of the inital SoC.
output = api.run_sim(
base_battery="Molicel P45B",
cycler=cycler_dict,
designs=designs,
initialVoltage=3.5,
# initialSoC=0.5,
initialTemperature_degC=25.0,
)
Running...: 100%|██████████| 1/1 [00:06<00:00, 6.79s/ designs]
Lets take a look at the current profile, the discharge current for the baseline cell is lower since it has a lower nominal capacity compared to the virtual cell we have decided to call "Lower NP".
output.plot_dynamic_response("Charge current [A]")
output.plot_voltage_response()
output.dynamic_kpis("DCIR")
| Design | Resistance (Ω) | |
|---|---|---|
| 0 | Baseline | -0.025112 |
| 1 | Lower NP | -0.024430 |
Now lets look at the rate capacity for different discharging rates down to 2.6 V, stoarting from 100% SOC.
rate_capacity_results = []
for rate in [1.0, 2.0, 3.0]:
cycler_input = cycler.cc_dch(-1 * rate, 2.6)
output = api.run_sim(
base_battery="Molicel P45B",
cycler=cycler_input,
designs=designs,
initialSoC=1.0,
initialTemperature_degC=50.0,
)
dynamic_kpis = output.dynamic_kpis("RateCap")
rate_capacity_results.append(
{
"Rate": rate,
"Baseline": dynamic_kpis.query("Design == 'Baseline'")[
"Capacity (Ah)"
].values[0],
"Lower NP": dynamic_kpis.query("Design == 'Lower NP'")[
"Capacity (Ah)"
].values[0],
}
)
print(rate_capacity_results)
Running...: 0%| | 0/1 [00:00<?, ? designs/s]
Running...: 100%|██████████| 1/1 [00:06<00:00, 6.71s/ designs] Running...: 100%|██████████| 1/1 [00:06<00:00, 6.63s/ designs] Running...: 100%|██████████| 1/1 [00:06<00:00, 6.36s/ designs]
[{'Rate': 1.0, 'Baseline': np.float64(4.437207460417406), 'Lower NP': np.float64(4.606167420206067)}, {'Rate': 2.0, 'Baseline': np.float64(4.430937494478882), 'Lower NP': np.float64(4.600110445356491)}, {'Rate': 3.0, 'Baseline': np.float64(4.418827133956763), 'Lower NP': np.float64(4.587609971434871)}]
Lets compare the rated capacity over C-Rate
# Create a line plot using Plotly Express
fig = px.line(
rate_capacity_results, x="Rate", y=["Baseline", "Lower NP"], title="Rate Capacity"
)
# Show the plot
fig.show()