Skip to content

Circuit fitting

pypalmsens.fitting

This module contains the public api for circuit fitting.

Classes:

  • CircuitModel

    Fit an equivalent circuit model.

  • FitResult

    Container for fitting results.

  • Parameter

    Set or update Parameter attributes.

  • Parameters

    Tuple-like container class for parameters.

CircuitModel dataclass

CircuitModel(cdc: str, algorithm: Literal['leastsq', 'nelder-mead'] = 'leastsq', max_iterations: int = 500, min_delta_error: float = 1e-09, min_delta_step: float = 1e-12, min_freq: None | float = None, max_freq: None | float = None, tolerance: float = 0.0001, lambda_start: float = 0.01, lambda_factor: float = 10.0, _last_result: None | FitResult = None, _last_psfitter: None | FitAlgorithm = None)

Fit an equivalent circuit model.

The class takes a CDC string as a required argument to set up the model.

The other parameters are optional and can be used to tweak the minimization. The model supports fitting over a specified frequency range and adjustment of exit conditions (i.e. max # iterations, min delta error, min parameter step size).

Optionally you can change the initial values of the parameters, their min/max bounds or fix their value.

Example:

model = CircuitModel('R(RC)')
result = model.fit(eis_data)

Methods:

  • default_parameters

    Get default parameters. Use this to modify parameter values.

  • fit

    Fit circuit model.

Attributes:

algorithm class-attribute instance-attribute

algorithm: Literal['leastsq', 'nelder-mead'] = 'leastsq'

Name of the fitting method to use.

Valid values are: leastsq (Levenberg-Marquardt), nelder-mead

cdc instance-attribute

cdc: str

Sets the circuit specified in the CDC string.

For more information, see: https://www.utwente.nl/en/tnw/ims/publications/downloads/cdc-explained.pdf

lambda_factor class-attribute instance-attribute

lambda_factor: float = 10.0

Lambda Scaling Factor. Levenberg-Marquardt only (default = 10).

lambda_start class-attribute instance-attribute

lambda_start: float = 0.01

Start lambda value. Levenberg-Marquardt only (default = 0.01).

last_psfitter property

last_psfitter

Store reference to last SDK fitting object.

last_result property

last_result

Store last fit result.

max_freq class-attribute instance-attribute

max_freq: None | float = None

Maximum fitting frequency in Hz.

max_iterations class-attribute instance-attribute

max_iterations: int = 500

Maximum number of iterations.

Minimization terminates once it reaches this number of steps (default = 500).

min_delta_error class-attribute instance-attribute

min_delta_error: float = 1e-09

Minimum convergence error.

Minimization converges if the residual (squared difference) falls below this value (default = 1e-9).

min_delta_step class-attribute instance-attribute

min_delta_step: float = 1e-12

Minimum convergence step.

Minimization converges if the difference in parameter values falls below this value (default = 1e-12).

min_freq class-attribute instance-attribute

min_freq: None | float = None

Minimum fitting frequency in Hz.

tolerance class-attribute instance-attribute

tolerance: float = 0.0001

Convergence tolerance. Nelder-Mead only (default = 1e-4).

default_parameters

default_parameters() -> Parameters

Get default parameters. Use this to modify parameter values.

Returns:

  • parameters ( Parameters ) –

    Default parameters for CDC.

Source code in src/pypalmsens/_fitting.py
342
343
344
345
346
347
348
349
350
def default_parameters(self) -> Parameters:
    """Get default parameters. Use this to modify parameter values.

    Returns
    -------
    parameters : Parameters
        Default parameters for CDC.
    """
    return Parameters(self.cdc)

fit

fit(data: EISData, *, parameters: None | Sequence[float] | Parameters = None) -> FitResult

Fit circuit model.

Parameters:

  • data
    (EISData) –

    Input data.

  • parameters
    (Optional[Sequence[float] | Parameters], default: None ) –

    Optional initial parameters for fit. Can be passed as Parameters object or list of values.

Returns:

  • result ( FitResult ) –

    Returns dataclass with fit results. Can also be accessed via .last_result.

Source code in src/pypalmsens/_fitting.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
def fit(
    self, data: EISData, *, parameters: None | Sequence[float] | Parameters = None
) -> FitResult:
    """Fit circuit model.

    Parameters
    ----------
    data : EISData
        Input data.
    parameters : Optional[Sequence[float] | Parameters]
        Optional initial parameters for fit. Can be passed as
        `Parameters` object or list of values.

    Returns
    -------
    result : FitResult
        Returns dataclass with fit results. Can also be accessed via `.last_result`.
    """
    if not data.frequency_type == 'Scan':
        raise ValueError(
            f'Fit only supports EIS scans at a fixed potential, got {data.frequency_type=}.'
        )
    if not data.scan_type == 'Fixed':
        raise ValueError(
            f'Fit only supports EIS scans at a fixed potential, got {data.scan_type=}.'
        )

    opts = self._psfitoptions(data=data, parameters=parameters)

    fitter = PSFitting.FitAlgorithm.FromAlgorithm(opts)
    fitter.ApplyFitCircuit()
    self._last_psfitter = fitter
    self._last_result = FitResult.from_psfitresult(fitter.FitResult, cdc=self.cdc)
    return self._last_result

FitResult dataclass

FitResult(cdc: str, parameters: list[float], error: list[float], chisq: float, n_iter: int, exit_code: str)

Container for fitting results.

Methods:

  • from_eisdata

    Construct fitresulf from EISData.

  • from_psfitresult

    Construct fitresult from SDK FitResult.

  • get_bode_phase

    Calculate observed and calculated Bode curve phase vs Frequency.

  • get_bode_z

    Calculate observed and calculated Bode curve Z vs Frequency.

  • get_nyquist

    Calculate observed and calculated nyquist curves.

  • get_psmodel

    Get SDK Circuit model object.

  • plot_bode

    Make bode plot using matplotlib.

  • plot_nyquist

    Make nyquist plot using matplotlib.

Attributes:

cdc instance-attribute

cdc: str

Circuit model CDC values.

chisq instance-attribute

chisq: float

Chi-squared goodness of fit statistic.

error instance-attribute

error: list[float]

Error (%) on parameters.

exit_code instance-attribute

exit_code: str

Exit code for the minimization.

n_iter instance-attribute

n_iter: int

Total number of iterations.

parameters instance-attribute

parameters: list[float]

Optimized parameters for CDC.

from_eisdata classmethod

from_eisdata(data: EISData)

Construct fitresulf from EISData.

Source code in src/pypalmsens/_fitting.py
137
138
139
140
141
142
143
144
145
146
147
@classmethod
def from_eisdata(cls, data: EISData):
    """Construct fitresulf from EISData."""
    return cls(
        cdc=data.cdc,
        parameters=data.cdc_values,
        chisq=0,
        error=[0.0 for _ in data.cdc_values],
        exit_code='',
        n_iter=0,
    )

from_psfitresult classmethod

from_psfitresult(result: FitResult, cdc: str)

Construct fitresult from SDK FitResult.

Source code in src/pypalmsens/_fitting.py
125
126
127
128
129
130
131
132
133
134
135
@classmethod
def from_psfitresult(cls, result: PSFitting.FitResult, cdc: str):
    """Construct fitresult from SDK FitResult."""
    return cls(
        cdc=cdc,
        chisq=result.ChiSq,
        exit_code=result.ExitCode.ToString(),
        n_iter=result.NIterations - 1,
        parameters=list(result.FinalParameters),
        error=list(result.ParameterSDs),
    )

get_bode_phase

get_bode_phase(data: EISData) -> tuple[Curve, Curve]

Calculate observed and calculated Bode curve phase vs Frequency.

Parameters:

  • data
    (EISData) –

    Input EIS data.

Returns:

  • calc, meas : tuple[Curve, Curve]

    Returns the nyquist curve calculated from the model parameters and the measured curve from the EIS data.

Source code in src/pypalmsens/_fitting.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
def get_bode_phase(self, data: EISData) -> tuple[Curve, Curve]:
    """Calculate observed and calculated Bode curve phase vs Frequency.

    Parameters
    ----------
    data : EISData
        Input EIS data.

    Returns
    -------
    calc, meas : tuple[Curve, Curve]
        Returns the nyquist curve calculated from the model parameters
        and the measured curve from the EIS data.
    """
    psmodel = self.get_psmodel(data=data)
    curves = psmodel.GetCurvePhaseOverFrequency(False)
    calc, meas = (Curve(pscurve=pscurve) for pscurve in curves)
    return calc, meas

get_bode_z

get_bode_z(data: EISData) -> tuple[Curve, Curve]

Calculate observed and calculated Bode curve Z vs Frequency.

Parameters:

  • data
    (EISData) –

    Input EIS data.

Returns:

  • calc, meas : tuple[Curve, Curve]

    Returns the nyquist curve calculated from the model parameters and the measured curve from the EIS data.

Source code in src/pypalmsens/_fitting.py
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def get_bode_z(self, data: EISData) -> tuple[Curve, Curve]:
    """Calculate observed and calculated Bode curve Z vs Frequency.

    Parameters
    ----------
    data : EISData
        Input EIS data.

    Returns
    -------
    calc, meas : tuple[Curve, Curve]
        Returns the nyquist curve calculated from the model parameters
        and the measured curve from the EIS data.
    """
    psmodel = self.get_psmodel(data=data)
    curves = psmodel.GetCurveZabsOverFrequency(False)
    calc, meas = (Curve(pscurve=pscurve) for pscurve in curves)
    return calc, meas

get_nyquist

get_nyquist(data: EISData) -> tuple[Curve, Curve]

Calculate observed and calculated nyquist curves.

Parameters:

  • data
    (EISData) –

    Input EIS data.

Returns:

  • calc, meas : tuple[Curve, Curve]

    Returns the nyquist curve calculated from the model parameters and the measured curve from the EIS data.

Source code in src/pypalmsens/_fitting.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
def get_nyquist(self, data: EISData) -> tuple[Curve, Curve]:
    """Calculate observed and calculated nyquist curves.

    Parameters
    ----------
    data : EISData
        Input EIS data.

    Returns
    -------
    calc, meas : tuple[Curve, Curve]
        Returns the nyquist curve calculated from the model parameters
        and the measured curve from the EIS data.
    """
    psmodel = self.get_psmodel(data=data)
    curves = psmodel.GetNyquist()
    calc, meas = (Curve(pscurve=pscurve) for pscurve in curves)
    return calc, meas

get_psmodel

get_psmodel(data: EISData) -> CircuitModel

Get SDK Circuit model object.

Source code in src/pypalmsens/_fitting.py
149
150
151
152
153
154
155
def get_psmodel(self, data: EISData) -> PSFitting.Models.CircuitModel:
    """Get SDK Circuit model object."""
    psmodel = PSFitting.Models.CircuitModel()
    psmodel.SetEISdata(data._pseis)
    psmodel.SetCircuit(self.cdc)
    psmodel.SetInitialParameters(self.parameters)
    return psmodel

plot_bode

plot_bode(data: EISData) -> Figure

Make bode plot using matplotlib.

Parameters:

  • data
    (EISData) –

    Input EIS data.

Returns:

  • fig ( Figure ) –

    Returns matplotlib figure object. use fig.show() to render plot.

Source code in src/pypalmsens/_fitting.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
def plot_bode(self, data: EISData) -> figure.Figure:
    """Make bode plot using matplotlib.

    Parameters
    ----------
    data : EISData
        Input EIS data.

    Returns
    -------
    fig : fig.Figure
        Returns matplotlib figure object. use `fig.show()` to render plot.
    """
    import matplotlib.pyplot as plt

    calc_z, meas_z = self.get_bode_z(data=data)
    calc_ph, meas_ph = self.get_bode_phase(data=data)
    fig, ax1 = plt.subplots()
    _ = ax1.set_title('Bode plot')
    _ = ax1.set_xscale('log')

    _ = calc_z.plot(ax=ax1, legend=False, color='C0')
    _ = meas_z.plot(ax=ax1, marker='^', linestyle='None', color='C0', legend=False)

    ax2 = ax1.twinx()
    _ = calc_ph.plot(ax=ax2, legend=False, color='C1')
    _ = meas_ph.plot(ax=ax2, marker='^', linestyle='None', color='C1', legend=False)

    fig.legend()
    return fig

plot_nyquist

plot_nyquist(data: EISData) -> Figure

Make nyquist plot using matplotlib.

Parameters:

  • data
    (EISData) –

    Input EIS data.

Returns:

  • fig ( Figure ) –

    Returns matplotlib figure object. use fig.show() to render plot.

Source code in src/pypalmsens/_fitting.py
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
def plot_nyquist(self, data: EISData) -> figure.Figure:
    """Make nyquist plot using matplotlib.

    Parameters
    ----------
    data : EISData
        Input EIS data.

    Returns
    -------
    fig : fig.Figure
        Returns matplotlib figure object. use `fig.show()` to render plot.
    """
    import matplotlib.pyplot as plt

    calc, meas = self.get_nyquist(data=data)
    fig, ax = plt.subplots()
    _ = ax.set_title('Nyquist plot')

    _ = calc.plot(ax=ax)
    _ = meas.plot(ax=ax, marker='^', linestyle='None')

    return fig

Parameter dataclass

Parameter(symbol: str, value: None | float = None, min: None | float = None, max: None | float = None, fixed: None | bool = None)

Set or update Parameter attributes.

Attributes:

  • fixed (None | bool) –

    If True, fix the value for this parameter.

  • max (None | float) –

    Maximum (upper bound) for the parameter.

  • min (None | float) –

    Minimum (lower bound) for the parameter.

  • symbol (str) –

    Name of the parameter (not used in minimization).

  • value (None | float) –

    Initial value of the parameter.

fixed class-attribute instance-attribute

fixed: None | bool = None

If True, fix the value for this parameter.

max class-attribute instance-attribute

max: None | float = None

Maximum (upper bound) for the parameter.

min class-attribute instance-attribute

min: None | float = None

Minimum (lower bound) for the parameter.

symbol instance-attribute

symbol: str

Name of the parameter (not used in minimization).

value class-attribute instance-attribute

value: None | float = None

Initial value of the parameter.

Parameters

Parameters(cdc: str)

              flowchart TD
              pypalmsens.fitting.Parameters[Parameters]

              

              click pypalmsens.fitting.Parameters href "" "pypalmsens.fitting.Parameters"
            

Tuple-like container class for parameters.

This class is instantiated from the CDC code and contains default parameters. This ensures that the length and type of parameters match that of CircuitModel. Update the parameters in this class and pass to CircuitModel.fit().

Parameters:

  • cdc

    (str) –

    Genererate fitting parameters for this CDC.

Attributes:

  • cdc (str) –

    CDC code used to generate parameter listing.

Source code in src/pypalmsens/_fitting.py
70
71
72
73
74
75
76
77
78
def __init__(self, cdc: str):
    self.cdc: str = cdc
    """CDC code used to generate parameter listing."""

    model = PSFitting.Models.CircuitModel()
    model.SetCircuit(cdc)
    self._parameters = tuple(
        Parameter._from_psparameter(psparam) for psparam in model.InitialParameters
    )

cdc instance-attribute

cdc: str = cdc

CDC code used to generate parameter listing.