Publication-Grade Electrochemical Impedance Spectroscopy Platform
Story · What's New · Capabilities · Workflow · Benchmarks · Applications · Comparison · Installation · Citation
ZScope was not designed in the abstract. It was born from a real experimental problem.
During an electrochemical study, I needed to capture a baseline EIS spectrum at the start of a reaction — then measure six more spectra at different oxidation states as the reaction progressed. Each spectrum represented a distinct state of the system, and together they told the story of a mechanism evolving in time.
The analysis became a frustration. Working through seven spectra with existing tools was slow, disjointed, and offered no intuitive sense of how parameters evolved across the series. There was no way to interactively explore the relationship between circuit components and spectrum shape — to build the physical intuition that makes EIS meaningful.
I kept thinking: what if I could draw a circuit, move a slider, and watch the simulated Nyquist plot respond in real time — overlaid on my experimental data? Not as a fitter, but as a lens for understanding. A way to arrive at a physically motivated starting point before handing off to a numerical optimizer.
That idea became the first version of ZScope.
As the tool took shape, it grew. The fitting engine followed — built with the same insistence on reliability and physical transparency. Then Bayesian uncertainty quantification, because a parameter without an honest uncertainty estimate has limited scientific value. Then data validation, custom components, automatic circuit suggestion, and structured reporting.
Version 3.0 finally closes the loop on the problem that started it. Those seven spectra were never seven separate experiments — they were one measurement with something varying across it. ZScope now treats a set of spectra as the series it is: record what changed between them, fit them all in one pass, and read the physics off a trend rather than off a single curve.
ZScope is the tool I needed during that experiment. It is free, and I hope it gives other researchers something better than what was available to me.
Distribution: ZScope is released as a ready-to-install application for Windows. Source code is not publicly distributed. Full scientific documentation, validation benchmarks, and an in-app help manual are provided so you can trust what happens inside.
ZScope 2.x was a very good tool for fitting one spectrum. Version 3.0 is about everything around that: understanding what your circuit is doing, controlling how it is fitted, deciding which circuit is right — and treating a set of spectra as a series.
Record what varied. A dataset used to be a spectrum and nothing else. It can now carry what it was measured at — temperature, bias, elapsed time, concentration, current density, cycle number, partial pressure, pH — entered for the whole set in one grid rather than one dialog per file. Values can be read out of the file names, and where a name carries the number without a unit (cell_A_873_run1.txt), type the first one and ZScope learns where it sits and fills the rest. Units are converted for you: enter 600 °C and an Arrhenius plot receives 873.15 K.
Fit the whole series in one pass. ⚡ Fit All Datasets applies the circuit on the canvas to every spectrum, seeding each fit from the previous one's result. Ordered by your series variable, consecutive spectra differ by one step, so the last fit is genuinely close to the next — faster and far steadier than a set of independent fits, and the reason the run is sequential rather than parallel. A spectrum that fails is marked and skipped rather than stopping the run, and a failed fit is never carried forward as a seed.
Series Analysis 📈 — plot any fitted parameter against whatever varied and fit a trend:
| Model | Gives you |
|---|---|
| Arrhenius | Activation energy in eV and kJ/mol |
| Arrhenius ln(σT) | The convention for ionic conductors |
| Mott–Schottky | Flat-band potential and dopant density |
| Power law | Reaction order against pO₂ or current density |
| Exponential | Degradation rate and half-life |
| Linear | The neutral choice |
Y can be a single parameter, the automatic sum of every resistance, or a combination you build by clicking — R2 + R3 for a partial sum, Rct × Cdl for a time constant reported in seconds — and combinations can be named and kept.
The window is careful about what it will not claim: datasets you exclude are listed separately from ones that could not supply a point; a series where every spectrum shares the same X value is refused rather than fitted; an uncertainty as large as its own value is reported as not determined instead of printed as a measurement; and a two-point fit says outright that its R² of 1 means nothing.
Compare circuit models ⚖ — adding a component almost always lowers χ². That is not evidence it is real. Every fit is now remembered as a candidate and ranked by AICc (or AIC, or BIC) with Δ and Akaike weights, so "two arcs or three?" gets an answer instead of a lower residual. Any candidate can be put back on the canvas. Models fitted to different data are refused rather than ranked — a truncated fit has a lower AIC simply because it has less to explain.
Deconvolve overlapping DRT peaks 🔬 — peak detection integrates between the valleys, so two processes less than about a decade apart merge into one bump and the split between them is arbitrary. Since the area is the resistance, a wrong split is a wrong R that does not look wrong, because the total is still right. Deconvolution fits the whole γ(τ) curve with a sum of R‖CPE peaks instead, separating them by shape. On two processes 0.3 decades apart, detection reports one of 330 Ω where there are really two, of 120 and 200 Ω; deconvolution recovers both.
And you can do it by hand, on the plot: drag a peak sideways to move its time constant, up and down to change its resistance, click the curve to add one where the model falls short, then refit. Deciding how many processes there are is a judgement your eye makes better than any criterion — a criterion can only ever say "more terms fit better".
Build a circuit from the DRT 🧩 — the DRT already knows how many processes there are and where they sit. Each peak becomes an R‖CPE branch with R from the peak area, τ from its position, and α recovered from its width — a ZARC has an analytic DRT whose width depends only on α, so the measured width inverts to the exponent that produced it.
Control where the fit searches — by default, fitting spreads its restarts across each parameter's whole allowed range, which means the result barely depends on what you entered. A new Search scope control changes that: Anchored draws restarts near your values, Local runs a single fit from them. It is what makes a DRT-derived circuit and a sequential sweep worth doing.
See what a component does — double-click a part on the canvas and the plots show where it acts: the stretch of the Nyquist curve it governs redrawn thick and bright, the frequency band it dominates shaded on Bode and Phase, and faint ghost curves showing the spectrum with that component ten times larger and ten times smaller. Computed from your actual circuit rather than a textbook rule, so it stays correct for nested ladders, transmission lines and custom components. A component with no measurable effect says so — a quick way to spot an element left dangling.
Change a parameter by dragging the plot — the marker at the point of strongest influence can be dragged, and the component's value follows with the curve updating live. One undo step for the whole gesture.
Simulation Report — the fit report stops at the edge of your data. This one covers the full simulation grid, updates live, and labels every row fitted, measured or extrapolated, so a number predicted beyond your measurement is never mistaken for one the fit was constrained by.
Normalize by sample geometry — an impedance in ohms describes your specimen, not your material. Enter the geometry once and the whole report converts: area-specific resistance, resistivity, conductivity, and for corrosion work the corrosion current density and penetration rate per ASTM G102. Eight applications: solid pellets, single cells and electrodes, membranes, liquid conductivity cells, corrosion and coatings, batteries and supercapacitors, and in-plane thin films.
The conversion follows each quantity's unit rather than its name, so resistances scale up, capacitances and CPE admittances scale down, and a CPE exponent or a relaxation time is correctly left alone. The symmetric-cell convention ASR = R·A/2 applies to the electrode resistance and not the electrolyte, so nothing is halved on its own: you mark which components are electrode processes and every halved parameter is flagged (÷2). Geometry is stored per dataset, so a series of pellets each keeps its own.
Effective capacitance from a CPE — Q is an admittance in S·sα and means nothing on its own. The report converts it by both the Brug and Hsu–Mansfeld formulas, with τ and fpeak, and states which resistances each used. They can differ by tens of percent, and which applies is a modelling assumption that belongs to you.
Choose the imaginary sign, once — reports show Z″ or −Z″, switched with one checkbox. Headers always state which convention you are looking at, experimental and fitted always flip together, phase follows, and exports record the convention.
Every value states its unit, and derived values carry their uncertainty. Conductivity, icorr and effective capacitance inherit the uncertainty of the parameter they came from — a derived value with a blank error column beside a fitted one that has an error reads as the more certain of the two.
DRT against τ or frequency, switchable instantly with peak markers following. Scientific notation everywhere: type 1e-12, 1E-12, 1*10^-12 or a decimal comma; log-scaled parameters step ten clicks per decade. Each dataset keeps its own frequency range, saved with the project. Circuit notation explains its errors, showing the offending character and offering the legal rewritings rather than guessing. The dataset panel opens itself when a session becomes multi-dataset.
Note on precision: a defect in the parameter entry boxes rounded every value below a nanounit to zero — and editing that row's bounds could write the zero back onto the component. Capacitances, CPE admittances, inductances and sub-nanosecond time constants were affected. If you have fits with parameters in that range, please re-run them.
Previously — What's New in 2.2.0
Save & Open Project — an entire session now lives in one .zscope file: every loaded dataset with its circuit, its fit and Bayesian results, its DRT analysis, and its import column mapping. Reopen it and everything is where you left it. The file is an ordinary ZIP archive with a readable JSON manifest inside, so it can be inspected without ZScope, and numerical arrays are stored exactly — a reloaded project is bit-for-bit identical to the one you saved.
Export datasets as separate project files — split a batch into one independently-reopenable project per dataset. Unlike CSV export, each file keeps that dataset's circuit, fit and DRT results with it.
Paste data from the clipboard — copy a block of cells in Excel, LibreOffice, Origin or a text editor and press Ctrl+V; the import dialog opens on the pasted table. Separator and decimal convention are detected automatically, including semicolon-separated European exports with decimal commas (1,0E+05;10,5), which a naive parser reads off by a factor of ten.
Import many files at once — select or drag in a whole folder of spectra. ZScope reads each one, detects its columns, and shows a review list with point counts and frequency ranges before anything loads.
Import source tracking — every spectrum records how it was obtained: columns detected automatically, columns chosen by you, or data values edited by hand.
Drag and drop now asks — dropping files offers Add or Replace. Closing the application offers to save unsaved work first.
Previously — What's New in 2.1.0
AI-enhanced circuit proposer — local and online AI now assist the proposer in analysing your spectrum and suggesting equivalent circuit models.
Bring your own AI account — import and connect a personal or enterprise AI account to power the proposer.
New benchmark suite — integrated benchmarks for rigorously evaluating, comparing, and validating circuit model performance.
Upgraded Fitting, DRT and Kramers–Kronig evaluation — improved accuracy, better edge-case handling, and more robust metrics.
Major fitting speed-up for large circuits — the Jacobian is now derived analytically from the circuit rather than approximated by finite differences, costing one linear solve instead of one per parameter. Circuits with 10+ free parameters fit roughly 20–35× faster.
📈 Series AnalysisA single fit gives parameters. A series of fits gives physics. Record what varied between your spectra, fit them all in one pass, then read the trend: activation energy from temperature, flat-band potential from bias, degradation rate from time, reaction order from partial pressure.
|
🖥️ Real-Time Interactive SimulationThe feature that started it all. Draw an equivalent circuit on the visual canvas, set your parameters, and the Nyquist, Bode, and Phase plots update instantly — with your experimental data overlaid.
|
||||||||||||||||
🎯 Advanced Fitting EngineAn escalating optimizer: exact, inexpensive methods first — global search engaged only when a fit fails quality acceptance.
Search scope now controls whether your starting values matter: Global, Anchored, or Local. Fit All Datasets runs a whole series, each fit seeded from the last. |
⚖️ Model ComparisonAdding a component almost always lowers χ² — that is not evidence it belongs. Every fit is remembered as a candidate and ranked by an information criterion that charges each parameter against the improvement it buys.
|
||||||||||||||||
🔬 DRT with DeconvolutionThe distribution of relaxation times, plus the means to separate what it merges. Two processes less than a decade apart become one bump, and the valley split between them is arbitrary — a wrong resistance that does not look wrong, because the total is still right.
|
📐 Geometry NormalizationAn impedance in ohms describes your specimen. Divide out the geometry and you have the material. Eight applications — solid pellets, single cells, membranes, liquid conductivity cells, corrosion and coatings, batteries, in-plane thin films.
|
||||||||||||||||
✅ Kramers–Kronig ValidationBefore fitting any parameters, confirm your data is worth fitting. ZScope reconstructs Z(ω) from a Voigt (RC-ladder) basis that is KK-consistent by construction.
A systematic trend in the residuals points to drift or non-stationarity; random scatter is just noise. One keystroke (Ctrl+K), under 2 seconds. |
📊 Bayesian MCMC UncertaintyA single point estimate is not enough. ZScope uses the
|
||||||||||||||||
📥 Flexible Data ImportImport EIS data without fighting file formats. ZScope recognizes the native exports of most common potentiostats — Gamry, BioLogic, Autolab, Zahner, Ivium, CHI, PalmSens, PAR — and falls back to a smart generic parser.
|
🔧 Extensible Element Library
Custom elements are defined through a GUI designer, exported as |
||||||||||||||||
💾 Projects & Session PersistenceSave Project writes everything — datasets, circuits, fits, posteriors, DRT results, series variables, geometry, model candidates, import settings — into a single
|
🔎 Data TraceabilityEvery spectrum carries a record of how it entered the analysis — auto-detected columns, a mapping you chose, or values you edited by hand — visible during import, written to the log, and preserved in the project file. Reports state their own conventions too: the imaginary sign, the geometry a value was normalized by, and which parameters the symmetric-cell factor was applied to. Exports carry all of it, so a CSV opened months later is still unambiguous. |
Load Data ──▶ KK Validate ──▶ Build Circuit ──▶ Fit ──▶ MCMC ──▶ Export
│ │ │ │ │ │
auto-detect < 2 seconds real-time sim LHS+TRF+DE posterior txt/csv/
column format residual map overlay data warm-start credible json/PDF
Import batch ──▶ Series Variables ──▶ Fit All ──▶ Series Analysis ──▶ Export
│ │ │ │ │
many files at what varied: seeded from Arrhenius, trend + Eₐ
once, columns T, E, t, [C] the previous Mott–Schottky, with its
detected each per dataset spectrum power law uncertainty
- Import — one file, or a whole folder with columns detected per file
- Validate (Ctrl+K) — confirm linearity and stationarity before fitting anything
- Build your circuit — draw it, choose a preset, request an algorithmic suggestion, or derive one from the DRT
- Fit — configure weighting, loss, restarts, search scope and frequency band
- Compare models — is the extra element earning its place?
- Quantify uncertainty — Bayesian MCMC for full posteriors and convergence diagnostics
- Normalize — enter the sample geometry and read ASR, resistivity or conductivity
- Analyse the series — record what varied, fit them all, read the trend
- Export — publication-ready figures, parameter tables, structured reports, and a
.zscopeproject preserving the session
ZScope is validated against synthetic data with known ground-truth parameters, across five reference circuits, three noise models, and multiple noise levels — over 19,000 independent fits per full benchmark run. Every figure below is a repeated-trial result with an interval, not a single-seed example.
χ² computed against the true per-point noise σ used to generate the data. A correctly-specified model fitted to the noise floor gives 1.0.
| Noise level | χ²calibrated |
|---|---|
| 2% | 0.992 |
| 5% | 1.006 |
Optimizer started from an uninformed guess (0.2×–5× per parameter), not from the true values.
| Circuit | Worst parameter | Mean error |
|---|---|---|
| Randles | Cdl | 0.36% |
| Randles + Warburg | σW | 0.54% |
| CPE Randles | Q | 1.79% |
| Two-Time-Constants | C₂ | 3.98% |
All other parameters recover below 1%. The CPE exponent α recovers to 0.25%.
Whether the reported ± actually contains the true value at its nominal rate — measured, not assumed.
| Condition | Covariance estimator | Coverage (nominal 95%) |
|---|---|---|
| Well-behaved noise | Jacobian | 94.4% |
| Well-behaved noise | Robust sandwich | 93.1% |
| 5% contaminated points | Jacobian | 89.0% |
| 5% contaminated points | Robust sandwich | 94.2% |
The robust loss is the shipped default: it costs about a point of efficiency on clean data and recovers calibration entirely when data contains outliers.
How far apart two relaxation processes must be before the DRT resolves them as two peaks rather than one — the Rayleigh criterion analogue for impedance.
| Noise | Required τ₂/τ₁ |
|---|---|
| 0% | ≈ 10 |
| 1% | ≈ 16 |
| 2% | ≈ 27 |
| 5% | ≈ 75 |
Approximately τ₂/τ₁ ≈ 15 × (noise level in %). Below the limit the method fails conservatively — returning a single peak at the geometric mean with the combined resistance, rather than inventing structure. Version 3.0's deconvolution can separate peaks below this limit when you tell it how many there are, which is why it reports the peak count as a judgement rather than a result.
Where ZScope's methods have limits, the benchmarks report them. Kramers–Kronig testing reliably detects drift only once the distortion is large relative to measurement noise — a small drift is genuinely indistinguishable from noise, in any implementation. The Q–α correlation in CPE fitting reflects a real physical interdependence, not a software deficiency, and is detected and reported rather than hidden.
All benchmark data, comparison tables, and analysis scripts are available in benchmarks/ for independent verification.
| Domain | Typical Use | Series analysis gives you |
|---|---|---|
| Solid-State & Ceramics | Grain and grain-boundary separation · electrolyte conductivity | Activation energy from a temperature sweep |
| Battery Science | SEI/CEI characterization · charge-transfer kinetics · Li-ion diffusion | Rct growth against cycle number or SoC |
| Photovoltaics | Recombination dynamics · ion migration · hysteresis | Trends against bias or illumination |
| Corrosion Science | Polarization resistance · coating integrity · inhibitor screening | Rp and penetration rate against immersion time |
| Fuel Cells & Electrolyzers | Ohmic · kinetic · mass-transport deconvolution | Reaction order from a pO₂ or current-density series |
| Supercapacitors | Double-layer behaviour · porous electrode transmission-line analysis | Specific capacitance against mass or area |
| Semiconductors & Passive Films | Space-charge capacitance | Flat-band potential and dopant density (Mott–Schottky) |
| Bioelectrochemistry | Redox probe kinetics · biosensor interfacial impedance | Calibration curve against concentration |
| Mechanistic Studies | Multi-state or time-series EIS — the exact scenario ZScope was designed for | The whole point |
| Capability | Commercial Tools | Academic Scripts | ZScope |
|---|---|---|---|
| Real-time interactive simulation | Rarely | ✗ | ✅ Instantaneous |
| Series analysis (Arrhenius, Mott–Schottky, …) | ✗ | Manual | ✅ Built in, with uncertainties |
| Sequential batch fitting of a whole series | Rarely | Manual | ✅ One pass, seeded |
| Model comparison by AICc / AIC / BIC | ✗ | Manual | ✅ Ranked, with weights |
| DRT peak deconvolution | ✗ | Rarely | ✅ Interactive, on the plot |
| Geometry normalization (ASR, σ, icorr) | Rarely | Manual | ✅ Eight applications |
| Bayesian MCMC posteriors | Rarely | Manual | ✅ Full emcee engine |
| Kramers–Kronig validation | Limited | Manual | ✅ Integrated + residual maps |
| Global optimization (LHS+TRF+DE) | ✗ Local only | Variable | ✅ Escalating hybrid |
| Algorithmic circuit suggestion | Uncommon | ✗ | ✅ Spectral fingerprinting + DRT-derived |
| Custom elements (no coding) | Restricted | Script-level | ✅ GUI designer |
| Batch import of many spectra | Partial | Manual | ✅ Auto-detected per file |
| Paste data from clipboard | ✗ | ✗ | ✅ Locale-aware |
| Single-file session projects | Rarely | ✗ | ✅ Open, inspectable format |
| Published coverage & resolution limits | ✗ | ✗ | ✅ Measured and documented |
| Structured export (txt/csv/json/PDF) | Partial | Manual | ✅ Full |
| Cost | 💰 Annual license | Free | ✅ Free |
No Python. No package manager. No dependencies. Download, run the installer, open ZScope.
Projects and settings from 2.x open unchanged in 3.0.
macOS and Linux support are planned. If you work on those platforms, please open an issue — user demand shapes the roadmap.
If ZScope contributes to published research, please cite it so others can find it:
@software{zscope2026,
author = {Mohammadi, Tecush},
title = {ZScope: Publication-Grade Electrochemical Impedance Spectroscopy Analysis Platform},
year = {2026},
version = {3.0.0},
url = {https://github.com/Tecush/ZScope},
doi = {10.5281/zenodo.20357547}
}DOI: 10.5281/zenodo.20357547 — this DOI refers to ZScope as a whole and stays the same across releases.
Developer: Tecush Mohammadi Email: tecush@gmail.com GitHub: @Tecush Issues & feature requests: GitHub Issues
Questions about scientific methods, specific use cases, or validation data are welcome by email.
