Giter Club home page Giter Club logo

Comments (11)

mdmurbach avatar mdmurbach commented on June 12, 2024 1

Thanks for taking the time to right this up @ngamazza. This is a great suggestion and the right format for making it happen. 👍

In terms of where/what kind of documentation you’re suggesting, it sounds like the gap in docs currently is somewhere between the ”getting started with Impedance.py” and the actual function/api documentation?

Off the top of my head some additional intermediate types of ideas to get things going:

  • example use cases
    • looping through impedance data
    • validating, fitting, and visualizing an experiment
  • defining a custom model via a circuit string
  • contributing to impedance.py (forking, PRs, etc.)

@anyone have other thoughts on where we should expand the docs/have workflows they’d like to contribute?

from impedance.py.

dt-schwartz avatar dt-schwartz commented on June 12, 2024 1

from impedance.py.

BGerwe avatar BGerwe commented on June 12, 2024 1

Hi @ngamazza,

Ditto Matt's comments about being busy during the holidays, but I'm back now and working with impedance.py a lot. I agree we can spruce up our documents, but for now I want to address your question

I am not 100% sure how to pass the initial guess parameters of circuit elements, and sometimes get stuck between two errors such as
"in E, input list must be length 2"
"Initial guess length needs to be equal to {circuit_length}"
when building a new custom circuit

If you refer to the Plotting Nyquist plots of impedance spectra example, you'll see a custom circuit with initial parameters is defined in the third cell: circuit = CustomCircuit(initial_guess=[.01, .005, .1, .005, .1, .001, 200], circuit='R_0-p(R_1,C_1)-p(R_1,C_1)-W_1')
The initial guesses array is 7 elements long, but the circuit string only defines 6 elements. This arises from some circuit elements – like CPE (E) and warburg (W) – requiring two parameters. The circuit elements documents will tell you which elements fall under this scenario by having something like "Q = p[0] and α = p[1]" in the Notes section.

Regarding @mdmurbach 's list of example ideas

  • example use cases
    • looping through impedance data
    • validating, fitting, and visualizing an experiment
  • defining a custom model via a circuit string
  • contributing to impedance.py (forking, PRs, etc.)

Several of these are already addressed in the current examples. Defining custom models, fitting data, and visualizing data appear in the Fitting impedance spectra, and Plotting Nyquist plots of impedance spectra examples. Validating data is addressed in the Validation of EIS data example.

from impedance.py.

BGerwe avatar BGerwe commented on June 12, 2024 1

Hi @ngamazza,

Like @mdmurbach, I couldn't replicate the 'Initial guess length needs to be equal to {circuit_length}'' error. However, to Matt's point, if the α parameter of a CPE is initialized outside the [0,1] range you may get an error saying, "x0 is infeasible." Here I'll initialize the first α with a value of 10.

# read data
data = np.genfromtxt('data/exampleData.csv', delimiter=',')
f = data[:,0]
Z = data[:,1] + 1j*data[:,2]dfsdf

# define custom circuit
from impedance.circuits import CustomCircuit
circuit = CustomCircuit(initial_guess=[250, 60, 0.00002, 10, 100, 0.0002, 0.1],
                              circuit='R0-p(R1,E1)-p(R2,E2)')
print(circuit)

Circuit string: R0-p(R1,E1)-p(R2,E2)
Fit: False

Initial guesses:
R0 = 2.50e+02 [Ohm]
R1 = 6.00e+01 [Ohm]
E1_0 = 2.00e-05 [Ohm^-1 sec^a]
E1_1 = 1.00e+01 []
R2 = 1.00e+02 [Ohm]
E2_0 = 2.00e-04 [Ohm^-1 sec^a]
E2_1 = 1.00e-01 []

# fitting data
 circuit.fit(f, Z)

ValueError Traceback (most recent call last)
. . .
ValueError: x0 is infeasible.

But it should work if we change that α to something like 0.6

circuit = CustomCircuit(initial_guess=[250, 60, 0.00002, .6, 100, 0.0002, 0.1],
                              circuit='R0-p(R1,E1)-p(R2,E2)')
circuit.fit(f, Z)
print(circuit)

Circuit string: R0-p(R1,E1)-p(R2,E2)
Fit: True

Initial guesses:
R0 = 2.50e+02 [Ohm]
R1 = 6.00e+01 [Ohm]
E1_0 = 2.00e-05 [Ohm^-1 sec^a]
E1_1 = 6.00e-01 []
R2 = 1.00e+02 [Ohm]
E2_0 = 2.00e-04 [Ohm^-1 sec^a]
E2_1 = 1.00e-01 []

Fit parameters:
R0 = 1.59e-02 (+/- 2.10e-04) [Ohm]
R1 = 1.81e-02 (+/- 4.87e-04) [Ohm]
E1_0 = 5.62e+00 (+/- 3.22e-01) [Ohm^-1 sec^a]
E1_1 = 5.46e-01 (+/- 1.55e-02) []
R2 = 2.74e-01 (+/- 9.82e-02) [Ohm]
E2_0 = 4.13e+02 (+/- 2.77e+01) [Ohm^-1 sec^a]
E2_1 = 6.26e-01 (+/- 2.07e-02) []

from impedance.py.

mdmurbach avatar mdmurbach commented on June 12, 2024 1

Going to go ahead and close this issue, since the version 1.0 release added new examples and refreshed the docs.

from impedance.py.

mdmurbach avatar mdmurbach commented on June 12, 2024

Hi @dt-schwartz and @ngamazza, my apologies for the delay, was traveling through the holidays and missed your reply.

@dt-schwartz I think it could be a potentially interesting project, although I'm not sure what technical scope makes sense for the capstone team. On the more challenging end implementing a distribution of relaxation times (DRT) algorithm would be an awesome addition (there are examples of implementations, e.g. [Ciucci (2015), matlab], but this would be a relatively math intensive project). Other projects that come to mind are visualization (functions for Bode diagrams, interactive charts with Altair, creating circuit diagrams from user input, plotting fit residuals, etc.) or some statistical model selection (calculating an information criterion or something like that to determine best fitting model).

I can put together a more concrete project write up in the next few days if you think it still makes sense?

from impedance.py.

ngamazza avatar ngamazza commented on June 12, 2024

Hi everyone,
I'm also just back from vacations!

FIrst of all, thanks for the answers and the help!
I agree that what @mdmurbach suggested looks nice.
Maybe, in the part regarding looping through the data, then show that's possible to use a loop to collect the fit outputs in a single table/tsv? Though it is not essential.

@BGerwe: thanks for the detailed answer! Can I push maybe my luck and ask a follow up question?
My data shows roughly two arcs, and as a first attempt I used 'R0-p(R1,C1)-p(R2,C2)', but I'd probably get a better fit using CPEs, but I get an error when doing that.
This runs, and I'm then able to get a Nyquist plot with a code very similar to the one in the example

circuit = impedance.circuits.CustomCircuit(initial_guess=[250, 60, 0.00002, 100, 0.0002],
                              circuit='R0-p(R1,C1)-p(R2,C2)')

This, where I sub both Cs for Es and use 7 parameters, gets ''Initial guess length needs to be equal to {circuit_length}''

circuit = impedance.circuits.CustomCircuit(initial_guess=[250, 60, 0.00002, 10, 100, 0.0002, 0.1],
                              circuit='R0-p(R1,E1)-p(R2,E2)')

And, as it should, using 5 parameters gets "in E, input list must be length 2".

The full script (which will probably show that I'm a beginner...), is:

import os 
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import impedance


files = ['example.dat'] 

#run through the files, fit, plot and save
for filename in files:
    flnm1 = os.path.splitext(filename)[0]
    data_eis = pd.read_csv(filename, sep=('\t'), decimal = '.', skiprows =6)
    data_eis.columns= ['Freq', 'Re', 'Im', 'Amp', 'Pha', 'R(DC)', 'C', 'Bias', 'Bias']
    data_eis['neg_Imm_part'] = 0 - data_eis['Im']
    
    circuit = impedance.circuits.CustomCircuit(initial_guess=[250, 60, 0.00002,  100, 0.0002],
                              circuit='R0-p(R1,C1)-p(R2,C2)')

    data_eis_pos = data_eis[(data_eis.Im<0)]
    Z = data_eis_pos['Re'] + 1j* data_eis_pos['Im']
    circuit.fit (np.asarray(data_eis_pos['Freq']), np.asarray(Z))
    fig, ax = plt.subplots()
    ax = circuit.plot(f_data=np.asarray(data_eis['Freq']), Z_data=np.asarray(Z), 
                      conf_bounds='filled')
    ax.tick_params(axis='both', which='major', labelsize=16)
    print(circuit, file=open( flnm1 + ".txt", "a"))
    ax.grid(False)
    fig = ax.get_figure()
    fig.savefig(flnm1 + '_nyquist.png')
    plt.close()`

Thanks for the help, and happy new year!

from impedance.py.

mdmurbach avatar mdmurbach commented on June 12, 2024

HI @ngamazza,

I can't seem to reproduce the same error you're having with 7 initial guesses passed to a 2-CPE circuit. The code below works for me:

from impedance.circuits import CustomCircuit
from impedance.plotting import plot_nyquist
import matplotlib.pyplot as plt
import numpy as np

data = np.genfromtxt('./impedance_data/3.369V.csv', delimiter=',')
f = data[:, 0]
Z = data[:, 1] + 1j*data[:, 2]

# initialize circuit
# E (CPE) parameters are Q [1 and 10, below], alpha [0.9, below]
circuit = CustomCircuit(initial_guess=[.01, .01, 1, 0.9, .01, 10, 0.9],
                        circuit='R0-p(R1,E1)-p(R2,E2)')

# Fit circuit
circuit.fit(f, Z)
print(circuit)

# Plot results
Z_fit = circuit.predict(f)

fig, ax = plt.subplots(figsize=(5,5))
plot_nyquist(ax, f, Z, fmt='o')
plot_nyquist(ax, f, Z_fit)

plt.show()

image

One thing to note is that the parameters for a CPE (E) are Q [Ohm^-1 sec^a], alpha where alpha should be between 0 and 1. Could you try changing the initial guesses you're passing for alpha to something like 0.9?

from impedance.py.

mdmurbach avatar mdmurbach commented on June 12, 2024

@ngamazza I also think you might have an older version of impedance.py (based on the error message of "Initial guess length needs to be equal to {circuit_length}" which I think was fixed in v0.5, #40). Not sure if this is part of the error, but you can update your version with

pip install --upgrade impedance

from impedance.py.

BGerwe avatar BGerwe commented on June 12, 2024

@ngamazza I wrote up this example of looping through data sets, fitting them, and visualizing. I'm also a self-taught coder so these may not be best practices but they've worked well for me so far. Maybe @mdmurbach can give some advice on improvements if anything looks strange.

The most important feature is that you can use lists to store any kind of object including numpy arrays for data, and the circuit class objects that are used for storing the fit results. Here's a snippet of what that looks like

from impedance import preprocessing

# Initialize some empty lists for the frequencies and Z data

freqs = []
Zs = []

# Now loop through file names in our list and extract data one by one

for file_name in all_files:
    f, Z = preprocessing.readZPlot(file_name)
    freqs.append(f)
    Zs.append(Z)
    
# Check to see if we extracted data for all the files
print(np.shape(Zs), np.shape(all_files))

But you can see all the details in the Jupyter notebook and data I've attached in the zip file (unfortunately attaching Jupyter Notebooks and Zplot files are not supported through GitHub). Note: please place the data files in a subdirectory called "data", or change the direc variable to point where you're storing the data files.
Looping Files Example.zip

from impedance.py.

ngamazza avatar ngamazza commented on June 12, 2024

Hi @BGerwe and @mdmurbach ,

Great for the new example!
As soon as I get a bit more experienced in Python and the package I can maybe help with the examples.

On the other topic, changing the value of the parameter did not solve it but as I was playing around with impedance.py yesterday, trying to understand what's wrong, I noticed even the Nyquist example code gave me the same error.
I created a new environment, thinking that the problem must be with my installation and not the package, and I was able to run the same exact scripts normally, without the errors I described above.
I was hoping to see understand if some other package was creating the problem, but the scripts now work also in the other environments, strangely enough. I will be doing some fittings over the next days, and I'll see if I can replicate the error, playing around with the environments, or understand what caused it. In case, I'll post here.

Thanks for the help!

from impedance.py.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.