Analyse Data

EIS - Electrochemical Impedance Spectra

Circuit Fitting

class EisFitting(analysisConnection: AnalysisConnection = None)

Class which can fit models to impedance spectra.

This class uses the REST interface of the Zahner Analysis for fitting.

This class uses the Python logging module, which can be enabled and output with the following sample configuration.

import logging

if __name__ == "__main__":

    logging.basicConfig(
        filename='logfile.log',
        level=logging.DEBUG,
        format='%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S',
    )

    conn = AnalysisConnection(
        ip="127.0.0.1",
        port=8085,
        tryToConnect=True,
        tryToStart=True,
        onlineCheckUrl="/id",
        apiKey="MyKeyToPreventSomeoneElseRemotelyUsingMyAnalysis",
        buffer_size=32768,
        keep_jobs=10,
        timeToWaitForOnline=10,
        keepOpen=True)

    fitting = ImpedanceFitting(conn)
Parameters:

analysisConnection – Optional connection object to the Zahner Analysis. Not needed if Zahner Analysis is installed locally.

zhit(data: IsmImport = None, parameters: dict = {}, timeout: float = None) IsmImport

Performs the ZHIT evaluation.

ZHIT is a software tool that uses measured phase data to reconstruct the impedance spectrum. The reconstructed impedance spectrum is then compared to the measured impedance spectrum to validate the measurement and identify any artifacts.

Links to the topic ZHIT:

Parameter dictionary for optional parameters:

Key

Description

Smoothness

Factor with which smoothed. This must be determined empirically in the GUI.

NumberOfSamples

Number of samples used for the data. Default all samples.

parameters = {
    "Smoothness": 0.0002,
    "NumberOfSamples": 20
}
Parameters:
  • data – Data to which the ZHIT is applied.

  • parameters – Optional parameters for the ZHIT.

  • timeout – Timeout for the caculation.

fit(model: IsfxModelImport, data: IsmImport = None, fitParams: dict = {}, simulationParams: dict = {}, timeout: float = None) EisFittingResult

Performing the fit.

With this method the model is fitted to the data. The initial values and the model can be easily developed using the Zahner Analysis GUI.

The parameters are optional. You can also use only some optional parameters and omit others. Parameter dictionary for optional fit parameters:

Key

Description

UpperFrequencyLimit

Upper frequency limit up to which the data is used for fitting. Default highest frequency.

LowerFrequencyLimit

Lower frequency limit downto to which the data is used for fitting. Default lowest frequency.

DataSource

Selection of the data to be used for the fit. “original” or “smoothed” or “zhit”. Default “original”.

Smoothness

Factor with which smoothed. This must be determined empirically in the GUI.

NumberOfSamples

Number of samples used for the fit. Default all samples.

fitParams = {
    "UpperFrequencyLimit": 100000,
    "LowerFrequencyLimit": 1e-6,
    "DataSource": "zhit",  # "original", "smoothed" or "zhit"
    "Smoothness": 0.0002,
    "NumberOfSamples": 20
}

Parameter dictionary for optional simulation parameters:

Key

Description

UpperFrequencyLimit

Upper frequency limit up to which the model is simulated. Default highest frequency of data.

LowerFrequencyLimit

Lower frequency limit downto to which the model is simulated. Default lowest frequency of data.

NumberOfSamples

Number of samples used for the simulation. Default 100.

simulationParams = {
    "UpperFrequencyLimit": 10e3,
    "LowerFrequencyLimit": 1e-6,
    "NumberOfSamples": 150
}
Parameters:
  • model – Model which is fitted to the data.

  • data – Data to which the model is fitted.

  • fitParams – Explained in the previous text.

  • simulationParams – Explained in the previous text.

  • timeout – Timeout for the fit.

_startFit(model: IsfxModelImport, data: IsmImport, params: dict) str

Function which starts the fit.

This function sends the model, data and parameters to the Zahner Analysis via HTTP post request. The JobId assigned by Zahner Analysis is returned.

Parameters:
  • model – Model which is fitted to the data.

  • data – Data to which the model is fitted.

  • dict – Dictionary {“Fit”:fitParams, “Simulation”:simulationParams}.

Returns:

JobId

simulate(model: IsfxModelImport, simulationParams: dict, timeout: float = None) IsmImport

Simulate the model.

With this method, an impedance spectrum is generated from the model.

Parameter dictionary for simulation parameters:

Key

Description

UpperFrequencyLimit

Upper frequency limit up to which the model is simulated. Default highest frequency of data.

LowerFrequencyLimit

Lower frequency limit downto to which the model is simulated. Default lowest frequency of data.

NumberOfSamples

Number of samples used for the simulation. Default 100.

simulationParams = {
    "UpperFrequencyLimit": 10e3,
    "LowerFrequencyLimit": 1e-6,
    "NumberOfSamples": 150
}
Parameters:
  • model – Model to be simulated.

  • simulationParams – Explained in the previous text.

  • timeout – Timeout for the fit.

_startSimulation(model: IsfxModelImport, params: dict) str

Function which starts the simulation.

This function sends the model and parameters to the Zahner Analysis via HTTP post request. The JobId assigned by Zahner Analysis is returned.

Parameters:
  • model – Model to be simulated.

  • dict – Dictionary {“Simulation”:simulationParams}.

Returns:

JobId

_waitForJob(jobId: str, timeout: float = None)

Function which is waiting for the fit result.

This function polls the status of the fit operation and reads the fit result as JSON.

Parameters:
  • jobId – JobId.

  • timeout – Time for which polling should be done in seconds, or None for infinite.

Returns:

Fit result as JSON string.

_readFittedModel(jobId) IsfxModelImport

Reading the fitted model from the Zahner Analysis.

Reading is done via http get request.

Parameters:

jobId – JobId.

Returns:

Object from received data.

_readFitInputData(jobId) IsmImport

Reading the Samples used for fit from the Zahner Analysis.

Reading is done via http get request.

Parameters:

jobId – JobId.

Returns:

Object from received data.

_readSimulatedData(jobId) IsmImport

Reading the simulation data from the Zahner Analysis.

Reading is done via http get request.

Parameters:

jobId – JobId.

Returns:

Object from received data.

class EisFittingResult(fitResult: str, fittedModel: IsfxModelImport, fittedSimulatedData: IsmImport, fitInputData: IsmImport)

This class contains the results of the fit.

The constructor of this class is called by the fit method.

Parameters:
  • fitResult – Fit result as JSON string.

  • fittedModel – Model with the fitted parameters.

  • fittedSimulatedData – Data simulated from the model.

  • fitInputData – Data used for the fit.

getFitResultJson(fmt='json')

Get the fit result.

This function returns the fit result as JSON or as string.

The following is an example of the data returned. For each parameter of each element the value, unit, significance and error is returned. Also data for the overall fit result is returned.

{
  "model": {
    "C0": {
      "C": {
        "error": 15.151926309121153,
        "significance": 0.032274504286208844,
        "value": 0.05020110574526214,
        "value_unit": "F"
      }
    },
    "CPE0": {
      "C_eq": {
        "error": 1.055031648230169,
        "significance": 0.2519304540206341,
        "value": 0.06756234793290997,
        "value_unit": "F"
      },
      "α": {
        "error": 0.5970910562207303,
        "significance": 0.6845012405311864,
        "value": 0.7366826808067263,
        "value_unit": ""
      }
    },
    "FI0": {
      "W": {
        "error": 0.48845055246742036,
        "significance": 0.6408552251285363,
        "value": 0.04073380256581006,
        "value_unit": "Ωs^(-½)"
      },
      "k": {
        "error": 1.9687457791834184,
        "significance": 0.15899771929695322,
        "value": 0.0013854241183094132,
        "value_unit": "1/s"
      }
    },
    "L0": {
      "L": {
        "error": 2.8396295426843867,
        "significance": 0.6911809622435452,
        "value": 7.940027736136356e-07,
        "value_unit": "H"
      }
    },
    "R0": {
      "R": {
        "error": 1.5977793098280266,
        "significance": 0.07859404364129204,
        "value": 0.0036204263202214014,
        "value_unit": "Ω"
      }
    },
    "R1": {
      "R": {
        "error": 0.529684672149924,
        "significance": 0.9232302468243536,
        "value": 0.026830261706435942,
        "value_unit": "Ω"
      }
    },
    "R2": {
      "R": {
        "error": 0.18918999015755764,
        "significance": 0.4215958599730566,
        "value": 0.035941054916087775,
        "value_unit": "Ω"
      }
    }
  },
  "overall": {
    "impedance_error_max": 1.9436053656746468,
    "impedance_error_mean": 0.14339995178171594,
    "overall_error": 1.1323929422725485,
    "phase_error_max": 0.22001396123330905,
    "phase_error_mean": 0.018250258203149725
  }
}
Parameters:

fmt – “json” for json, else string.

Returns:

json or string.

getFittedModel() IsfxModelImport

Get the fitted model.

Returns:

The model.

getFittedSimulatedData() IsmImport

Get the fitted simulated data.

These data were generated by a simulation of the model.

Returns:

The data.

getFitInputData() IsmImport

Get the samples used for fitting.

These frequency points from the original data were used for the fit. These are the original measurement points used for the fit. These points were already smoothed or pre-processed with the ZHIT when it was set.

Returns:

The data.

save(path='', foldername='', exist_ok=True, saveFitResultJson=True, saveFittedModel=True, saveFittedSimulatedSamples=True, saveFitInputSamples=True, fitResultJsonFilename='fit_result.json', fittedModelFilename='fitted.isfx', fittedSimulatedDataFilename='fitted_simulated.ism', fitInputDataFilename='fit_samples.ism')

Save all fit data.

With this function, all the results files of the fit can be saved to the hard disk. It can be selected what all can be saved with. By default, everything is saved.

Parameters:
  • path – Path where a folder with the fit results will be created. This path can also be relative, as with all paths in Python.

  • foldername – Name of the folder in which the data will be saved.

  • exist_ok – Parameter of the os.makedirs function which is used to create the folder. If exist_ok is False, an FileExistsError is raised if the target directory already exists.

  • saveFitResultJson – If true, the json is stored under the filename of the variable fitResultJsonFilename.

  • saveFittedModel – If true, the model is stored under the filename of the variable fittedModelFilename.

  • saveFittedSimulatedSamples – If true, the simulated fitted data is stored under the filename of the variable fittedSimulatedDataFilename.

  • saveFitInputSamples – If true, the samples used for fit are stored under the filename of the variable fitInputDataFilename.

  • fitResultJsonFilename – Filename for the JSON with the fit result.

  • fittedModelFilename – Filename for the fitted model.

  • fittedSimulatedDataFilename – Filename for the data simulated with the model.

  • fitInputDataFilename – Filename for the data of the points used for the fit.

class EisFittingPlotter

Class with utility Nyquist and Bode plotting methods.

This class contains methods to display the fit results in the style of Zahner Analysis.

static plotBode(fittingResult: EisFittingResult, impedanceData: IsmImport = None, axes=None, zTogetherPhase=True, absPhase=True)

Plotting the data in the Bode plot.

For plotting matplotlib is used with the function zahner_analysis.plotting.impedance_plot.bodePlot(). With this function or also only with matplotlib the plot can be represented adapted. This method displays the plot in the standard Zahner Analysis design.

Either axes can be passed on which will be plotted, or a new figure with axes will be created automatically. The figure and the axes are always returned.

If the impedanceData is not passed, then the samples used for the fit are displayed.

The Zahner Analysis default setting impedance and phase in a plot and phase in magnitude can be deactivated with two parameters.

The following code block shows a few snippets as an example:

fig, ax = plt.subplots(2,2)

(fig, (impedanceAxis, phaseAxis)) = EisFittingPlotter.plotBode(fittingResult, axes=(ax[0,0],ax[1,0]))
(fig, (impedanceAxis, phaseAxis)) = EisFittingPlotter.plotBode(fittingResult, axes=(ax[0,1],ax[1,1]))
impedanceAxis.legend(["Measured Data", "Fitted Model"])
plt.show()

# or

(fig2, (impedanceAxis2, phaseAxis2)) = EisFittingPlotter.plotBode(fittingResult)
impedanceAxis2.legend(["Measured Data", "Fitted Model"])
fig2.set_size_inches(18, 10)
plt.show()
Parameters:
  • fittingResult – Fitting result object.

  • impedanceData – Optional impedance data for display.

  • axes – Tuple (impedanceAxis, phaseAxis) with impedance and phase axes object, or None if a new figure should be created.

  • zTogetherPhase – Default True to display phase and impedance in one plot.

  • absPhase – Default True to plot the absolute value of the phase.

Returns:

Tuple fig, axes

static plotNyquist(fittingResult: EisFittingResult, impedanceData: IsmImport = None, ax=None, minusNyquist=True, maximumAbsImpedance: float = None)

Plotting the data in the Nyquist plot.

For plotting matplotlib is used with the function zahner_analysis.plotting.impedance_plot.nyquistPlot(). With this function or also only with matplotlib the plot can be represented adapted. This method displays the plot in the standard Zahner Analysis design.

Either axes can be passed on which will be plotted, or a new figure with axes will be created automatically. The figure and the axes are always returned.

If the impedanceData is not passed, then the samples used for the fit are displayed.

The following code block shows a snippet as an example:

(fig, ax) = EisFittingPlotter.plotBode(fittingResult, maximumAbsImpedance=1)
ax.legend(["Measured Data", "Fitted Model"])
plt.show()
Parameters:
  • fittingResult – Fitting result object.

  • impedanceData – Optional impedance data for display.

  • ax – The axis on which to plot, or None to create a new figure.

  • minusNyquist – Default True to invert the imaginary part of the impedance.

  • maximumAbsImpedance – If the value is not None, only impedances whose absolute value is smaller than this value are plotted.

Returns:

Tuple fig, ax

Measurement Setup Compensation

class SetupCompensation(shortData: IsmImport | str | complex | None = None, openData: IsmImport | str | complex | None = None, loadData: IsmImport | str | complex | None = None, referenceData: IsmImport | str | complex | None = None, smoothingWindowLength: int | None = 5, smoothingPolyOrder: int | None = 3)

Object which contains the data and methods to compensate ism data.

⚠️WARNING⚠️

  • The results must be checked for plausibility, since incorrectly performed short, open and load measurements can also degrade the measurement results.

  • With a second measurement of a known object it must be verified if the compensation works or if it worsens the result.

  • The cable routing must not change after the calibration measurement. Since the cable routing and its impedance and parasitic properties are part of the calibration data.

  • For the best possible correction, the point density of the calibration measurements must be greater than or equal to that of the measurement to be corrected.

  • The calibration data are smoothed before the calculation, for this the window length and the polynomial order must be defined.

  • The order of the polynomial and the length of the window must be set by the user, this affects the result.

The formulas for the correction were derived from a theoretical four terminal network, which corresponds to the parasitic behavior of the measuring device and the setup. This formula is universal. It does not depend on the instrument used:

\[\begin{split}Z=\\frac{(Z_{\\text{short}}-Z_{\\text{meas}})(Z_{\\text{load}}-Z_{\\text{open}})}{(Z_{\\text{short}}-Z_{\\text{load}})(Z_{\\text{meas}}-Z_{\\text{open}})} \cdot Z_{\\text{load,ref}}\end{split}\]

Parameter

Description

\(Z_{\\text{short}}\)

Measurement without object. Short-circuited 4-wire test setup. CE, RE, WE power and WE sense are connected together.

\(Z_{\\text{open}}\)

Measurement without object. CE and RE as well as WE power and WE sense are connected to each other.

\(Z_{\\text{load}}\)

Measurement with a reference object of known defined impedance over the frequency range.

\(Z_{\\text{load,ref}}\)

Real impedance of the reference object of $Z_{text{load}}$ measurement.

\(Z_{\\text{meas}}\)

Measurement to be corrected.

\(Z\)

Measurement result corrected with the short, open and load data.

Basic Usage:

originalData = IsmImport("./ExampleData/500uR_measurement_pro.ism")

compensatedDataFileName = (
    "./ExampleData/500uR_measurement_pro_short_compensated.ism"
)

compensationData = SetupCompensation(
    shortData="./ExampleData/short_circuit_measurement_pro.ism"
)

compensatedData = compensationData.compensateIsm(originalData)
Parameters:
  • shortData – short data for correction, defaults to None.

  • openData – open data for correction, defaults to None.

  • loadData – load data for correction, defaults to None.

  • referenceData – real value of load data for correction, defaults to None. Here you can simply pass a number, for example 1 for 1 Ohm reference object.

  • smoothingWindowLength – Length of the smoothing window, defaults to 5.

  • smoothingPolyOrder – Length of the smoothing poly, defaults to 3.

setSmoothingWindowLength(value: int)

Sets the length of the smoothing window. Must be smaller than the poly length.

Parameters:

value – Length of the smoothing window.

getSmoothingWindowLength() int

Length of the smoothing window.

Returns:

Length of the smoothing window.

setSmoothingPolyOrder(value: int)

Sets the length of the smoothing polynomial. Must be greater than the window length.

Parameters:

value – Length of the smoothing poly.

getSmoothingPolyOrder() int

Length of the smoothing poly.

Returns:

Length of the smoothing poly.

compensateIsm(ism: IsmImport | str, conjugateShort: bool = False) IsmImport

Compensate ism Data.

This function can be used to apply the Short Open and Load data to the passed impedance data. You can then call this function several times to correct different data with the same data.

Parameters:
  • ism – Data which are to be compensated.

  • conjugateShort – Conjugate the short data., defaults to False.

Returns:

Impedance object which was compensated.