pybop-team / PyBOP

A parameterisation and optimisation package for battery models.
https://pybop-docs.readthedocs.io
BSD 3-Clause "New" or "Revised" License
68 stars 20 forks source link

Evaluating impedance at operating point #417

Closed noelhallemans closed 2 months ago

noelhallemans commented 3 months ago

Feature description

When evaluating the impedance of a model in a set of frequencies, this would ideally be possible at an operating point (SOC, temperature, C-rate). At the moment the operating point cannot be specified, the default is temperature = 25 degrees C, SOC=??, and C-rate is zero.

Evaluating impedance at a set of operating points would be very useful, also for parametrisation.

Motivation

Efficiently parametrising a model from multiple impedance spectra.

Possible implementation

No response

Additional context

No response

NicolaCourtier commented 3 months ago

Hi @noelhallemans, thanks for submitting this issue. As an initial workaround, here is an example of how to change the SOC based on the example in branch for #269.

import numpy as np

import pybop

# Define model
parameter_set = pybop.ParameterSet.pybamm("Chen2020")
model = pybop.lithium_ion.SPM(
    parameter_set=parameter_set, options={"surface form": "differential"}
)

# Fitting parameters
parameters = pybop.Parameters(
    pybop.Parameter(
        "Positive electrode thickness [m]",
        prior=pybop.Gaussian(60e-6, 1e-6),
        bounds=[20e-6, 90e-6],
    ),
    pybop.Parameter(
        "Negative electrode thickness [m]",
        prior=pybop.Gaussian(40e-6, 1e-6),
        bounds=[20e-6, 90e-6],
    ),
)

# Set the operating point by updating the initial concentrations
# WARNING: This method currently only works if the unknown parameters do not
# affect the calculation of the intiial concentrations.
model.build(init_soc=0.5, eis=True)
frequencies = np.logspace(-4, 5, 30)
simulation = model.simulateEIS(inputs=None, f_eval=frequencies)

# Form dataset
dataset = pybop.Dataset(
    {
        "Frequency [Hz]": frequencies,
        "Current function [A]": np.ones(30) * 0.0,
        "Impedance": simulation["Impedance"],
    }
)

# Generate problem, cost function, and optimisation class
signal = ["Impedance"]
problem = pybop.EISProblem(model, parameters, dataset, signal=signal)
cost = pybop.SumSquaredError(problem)
optim = pybop.CMAES(cost, max_iterations=100, max_unchanged_iterations=30)

x, final_cost = optim.run()
print("Estimated parameters:", x)

# Plot the nyquist
pybop.nyquist(problem, problem_inputs=x, title="Optimised Comparison")

# Plot convergence
pybop.plot_convergence(optim)

# Plot the parameter traces
pybop.plot_parameters(optim)

# Plot 2d landscape
pybop.plot2d(optim, steps=10)
BradyPlanden commented 2 months ago

The majority of this was included in #405, with just the c-rate functionality missing. This requires more thought and discussion, as such I'm closing this for the moment and opening a new issue for the c-rate additions.