Electrochemistry

ECMeasurement

The main TechniqueMeasurement class for electrochemistry is the ECMeasurement class. Subclasses of ECMeasurement include CyclicVoltammogram and CyclicVoltammogramDiff.

Direct-current electrochemistry measurements are characterized by the essential quantities being working-electrode current and potential (vs the reference electrode) as a function of time. Either current or potential can be controlled as the input variable, so the other acts as the response, and it is common to plot current vs potential, but in all cases both are tracked or controlled as a function of time. This results in the essential variables t (time), U (potential), and J (current). The main job of ECMeasurement and subclasses is to give standardized, convenient, and powerful access to these three variables for data selection, analysis, and visualization, regardless of which hardware the data was acquired with. At the present, ixdat does not yet offer specific functionality for electrochemical impedance spectroscopy (EIS) data.

The default plotter, ECPlotter, plots these variables. The default exporter, ECExporter, exports these variables as well as an incrementer for selecting data, selector.

Electrochemistry is the most thoroughly developed technique in ixdat. For in-depth examples of the functionality in the ECMeasurement class and its subclasses, see the following Tutorials:

The full module documentation is available below: The ec module.

CyclicVoltammogram

CyclicVoltammogram inherits from ECMeasurement and adds useful functionality for cyclic voltammetry analysis. This includes:

  • Current vs potential as the default plot() (same as plot_vs_potential() for an ECMeasurement).

  • A new counter, cycle, which counts cycles. At first this counter will point to a counter in the raw data, if available (Biologic, for example, exports a “cycle number” column). However, it is recommended to control this counter yourself using the redefine_cycle method. For example my_cv.redefine_cycle(start_potential=0.4, redox=False) makes cycle increment each time the potential passes 0.4 V in the cathodic direction.

  • The ability to select a cycle by indexing with an integer. For example my_cv[1] is a CyclicVoltammogram containing the first full cycle.

  • A new built-in series, scan_rate. This is derived automatically from potential and stored in V/s. It can be grabbed (t, v_scan = my_cv.grab("scan_rate")), indexed, or plotted like anything else.

  • An additional function select_sweep which can select a portion of the CV where the potential is scanned through a certain range.

  • A calc_capacitance function which uses the two above to calculate capacitance in Farads.

A common workflow is to read in cyclic voltammetry data as an ECMeasurement, convert it to a CyclicVoltammogram with the as_cv() method, tell it when to increment the cycle with redefine_cycle(), coplot potential and cycle vs time with plot_measurement() to see which cycle number to use, and then index to analyze or plot individual cycles. For example, to coplot two cycles (the sedond and the 50th) which both start and end at 0.2 V in the anodic direction:

>>> from ixdat import Measurement
>>> my_ec_meas = Measurement.read("my_data.mpt", reader="biologic")
>>> my_cv = my_ec_meas.as_cv()
>>> my_cv.redefine_cycle(start_potential=0.2, redox=True)
>>> my_cv.plot_measurement(J_name="cycle")   # co-plots potential and cycle counter
>>> ax = my_cv[2].plot(color="b", label="earlier")
>>> my_cv[50].plot(ax=ax, color="r", label="later")
>>> ax.legend()
>>> ax.get_figure().savefig("two_cycles.png")

Note that as_cv() is available for any hyphenated technique which inherits from ECMeasurement, such as ECMSMeasurement, and that all the data from the second technique (here MS) comes along for the ride when using the cycle counter to select data. For full documentation of the cyclic voltammetry module see below: cv_module

The ec module

Source: https://github.com/ixdat/ixdat/tree/user_ready/src/ixdat/techniques/ec.py

Example plots. left: ``ECMeasurement.plot_vs_potential()`` right: ``ECMeasurement.plot_measurement()``

left: ECMeasurement.plot_vs_potential() right: ECMeasurement.plot_measurement(). See tutorial

Module for representation and analysis of EC measurements

class ixdat.techniques.ec.ECCalibration(name=None, technique='EC', tstamp=None, measurement=None, RE_vs_RHE=None, A_el=None, R_Ohm=None)[source]

An electrochemical calibration with RE_vs_RHE, A_el, and/or R_Ohm

calibrate_series(key, measurement=None)[source]

Return a calibrated series for key based on the raw data in the measurement.

Key should be “potential” or “current”. Anything else will return None.

  • “potential”: the calibration looks up “raw_potential” in the measurement,

shifts it to the RHE potential if RE_vs_RHE is available, corrects it for Ohmic drop if R_Ohm is available, and then returns a calibrated potential series with a name indicative of the corrections done. - “current”: The calibration looks up “raw_current” in the measurement, normalizes it to the electrode area if A_el is available, and returns a calibrated current series with a name indicative of whether the normalization was done.

class ixdat.techniques.ec.ECMeasurement(name, *, ec_technique=None, RE_vs_RHE=None, R_Ohm=None, A_el=None, **kwargs)[source]

Class implementing electrochemistry measurements

TODO: Implement a unit library for current and potential, A_el and RE_vs_RHE

so that e.g. current can be seamlessly normalized to mass OR area.

The main job of this class is making sure that the ValueSeries most essential for visualizing and normal electrochemistry measurements (i.e. excluding impedance spec., RRDE, etc, which would need new classes) are always available in the correct form as the measurement is added with others, reduced to a selection, calibrated and normalized, etc. These most important ValueSeries are:

  • potential: The working-electrode potential typically in [V]. If ec_meas is an ECMeasurement, then ec_meas[“potential”] always returns a ValueSeries characterized by:

    • calibrated and/or corrected, if the measurement has been calibrated with the reference electrode potential (RE_vs_RHE, see calibrate) and/or corrected for ohmic drop (R_Ohm, see correct_ohmic_drop).

    • A name that makes clear any calibration and/or correction

    • Data which spans the entire timespan of the measurement - i.e. whenever EC data is being recorded, potential is there, even if the name of the raw ValueSeries (what the acquisition software calls it) changes. Indeed ec_meas[“potential”].tseries is the measurement’s definitive time variable.

  • current: The working-electrode current typically in [mA] or [mA/cm^2]. ec_meas[“current”] always returns a ValueSeries characterized by:

    • normalized if the measurement has been normalized with the electrode area (A_el, see normalize)

    • A name that makes clear whether it is normalized

    • Data which spans the entire timespan of the measurement

  • selector: A counter series distinguishing sections of the measurement program. This is essential for analysis of complex measurements as it allows for corresponding parts of experiments to be isolated and treated identically. selector in ECMeasurement is defined to increment each time one or more of the following changes:

    • loop_number: A parameter saved by some potentiostats (e.g. BioLogic) which allow complex looped electrochemistry programs.

    • file_number: The id of the component measurement from which each section of the data (the origin of each ValueSeries concatenated to potential)

    • cycle_number: An incrementer within a file saved by a potentiostat.

The names of these ValueSeries, which can also be used to index the measurement, are conveniently available as properties:

  • ec_meas.t_name is the name of the definitive time, i.e. that of the potential

  • ec_meas.E_name is the name of the raw potential

  • ec_meas.U_name is the name of the calibrated and/or corrected potential

  • ec_meas.I_name is the name of the raw current

  • ec_meas.J_name is the name of the normalized current

  • ec_meas.selector_name is the name of the default selector, i.e. “selector”

Numpy arrays from important DataSeries are directly accessible via attributes:

  • ec_meas.t for ec_meas[“potential”].t

  • ec_meas.U for ec_meas[“potential”].data

  • ec_meas.J for ec_meas[“current”].data

ECMeasurement comes with an ECPlotter which either plots potential and current against time (ec_meas.plot_measurement()) or plots current against potential (`ec_meas.plot_vs_potential()).

It turns out that keeping track of current, potential, and selector when combining datasets is enough of a job to fill a class. Thus, the more exciting electrochemistry-related functionality should be implemented in inheriting classes such as CyclicVoltammogram.

property A_el

The electrode area in [cm^2]

property J

The current ([mA] or [mA/cm^2]) numpy array of the measurement

property RE_vs_RHE

The refernce electrode potential on the RHE scale in [V]

property R_Ohm

The ohmic drop resistance in [Ohm]

property U

The potential [V] numpy array of the measurement

property aliases

A dictionary with the names of other data series a given name can refer to

as_cv()[source]

Convert self to a CyclicVoltammogram

calibrate_RE(RE_vs_RHE)[source]

Calibrate the reference electrode by providing RE_vs_RHE in [V].

property calibrations

The list of calibrations of the measurement.

The following is necessary to ensure that all EC Calibration parameters are joined in a single calibration when processing. So that “potential” is both calibrated to RHE and ohmic drop corrected, even if the two calibration parameters were added separately.

control_series_name = 'raw_potential'

Name (or alias) for main time variable or main time-dependent value variable, typically of the control technique

correct_ohmic_drop(R_Ohm)[source]

Correct for ohmic drop by providing R_Ohm in [Ohm].

default_exporter

alias of ECExporter

default_plotter

alias of ECPlotter

property ec_calibration

A calibration joining the first RE_vs_RHE, A_el, and R_Ohm

essential_series_names = ('t', 'raw_potential', 'raw_current')

Series which should always be present

property j

The current ([mA] or [mA/cm^2]) numpy array of the measurement

normalize_current(A_el)[source]

Normalize current to electrode surface area by providing A_el in [cm^2].

selection_series_names = ('file_number', 'loop_number', 'cycle number', 'Ns')

Name of the default things to use to construct the selector

property v

The potential [V] numpy array of the measurement

The cv module

Source: https://github.com/ixdat/ixdat/tree/user_ready/src/ixdat/techniques/cv.py

Example ``CyclicVoltammagramDiff`` plot

output of CyclicVoltammagramDiff.plot(). Tutorial.

class ixdat.techniques.cv.CyclicVoltammagram(*args, **kwargs)[source]
class ixdat.techniques.cv.CyclicVoltammogram(*args, **kwargs)[source]

Class for cyclic voltammetry measurements.

Onto ECMeasurement, this adds: - a property cycle which is a ValueSeries on the same TimeSeries as potential, which counts cycles. “cycle” becomes the Measurement’s sel_str. Indexing with integer or iterable selects according to cycle. - functions for quantitatively comparing cycles (like a stripping cycle, base cycle) - the default plot() is plot_vs_potential()

calc_capacitance(vspan)[source]

Return the capacitance in [F], calculated by the first sweeps through vspan

Parameters

vspan (iter of floats) – The potential range in [V] to use for capacitance

diff_with(other, v_list=None, cls=None, v_scan_res=0.001, res_points=10)[source]

Return a CyclicVotammagramDiff of this CyclicVotammagram with another one

Each anodic and cathodic sweep in other is lined up with a corresponding sweep in self. Each variable given in v_list (defaults to just “current”) is interpolated onto self’s potential and subtracted from self.

Parameters
  • other (CyclicVoltammogram) – The cyclic voltammogram to subtract from self.

  • v_list (list of str) – The names of the series to calculate a difference between self and other for (defaults to just “current”).

  • cls (ECMeasurement subclass) – The class to return an object of. Defaults to CyclicVoltammogramDiff.

  • v_scan_res (float) – see get_timed_sweeps()

  • res_points (int) – see get_timed_sweeps()

essential_series_names = ('t', 'raw_potential', 'raw_current', 'cycle')

Series which should always be present

get_timed_sweeps(v_scan_res=0.0005, res_points=10)[source]

Return list of [(tspan, type)] for all the potential sweeps in self.

There are three types: “anodic” (positive scan rate), “cathodic” (negative scan rate), and “hold” (zero scan rate)

Parameters
  • v_scan_res (float) – The minimum scan rate considered significantly different than zero, in [V/s]. Defaults to 5e-4 V/s (0.5 mV/s). May need be higher for noisy potential, and lower for very low scan rates.

  • res_points (int) – The minimum number of points to be considered a sweep. During a sweep, a potential difference of at least v_res should be scanned through every res_points points.

integrate(item, tspan=None, vspan=None, ax=None)[source]

Return the time integral of item while time in tspan or potential in vspan

Parameters
  • item (str) – The name of the ValueSeries to integrate

  • tspan (iter of float) – A time interval over which to integrate it

  • vspan (iter of float) – A potential interval over which to integrate it

plot_cycles(ax=None, cmap_name='jet')[source]

Plot the cycles on a color scale.

Parameters
  • ax (mpl.Axis) – The axes to plot on. A new one is made by default

  • cmap_name (str) – The name of the colormap to use. Defaults to “jet”, which ranges from blue to red

redefine_cycle(start_potential=None, redox=None, N_points=5)[source]

Build cycle which iterates when passing through start_potential

Parameters
  • start_potential (float) – The potential in [V] at which the cycle counter will iterate. If start_potential is not given, the cycle is just the selector inherited from ECMeasurement shifted to start at 0.

  • redox (bool) – True (or 1) for anodic, False (or 0) for cathodic. The direction in which the potential is scanning through start_potential to trigger an iteration of cycle.

  • N_points (int) – The number of consecutive points for which the potential needs to be above (redox=True) or below (redox=False) the start_potential for the new cycle to register.

select_sweep(vspan, t_i=None)[source]

Return the cut of the CV for which the potential is sweeping through vspan

Parameters
  • vspan (iter of float) – The range of self.potential for which to select data. Vspan defines the direction of the sweep. If vspan[0] < vspan[-1], an oxidative sweep is returned, i.e. one where potential is increasing. If vspan[-1] < vspan[0], a reductive sweep is returned.

  • t_i (float) – Optional. Time before which the sweep can’t start

selector_name = 'cycle'

Name of the default selector

series_constructors = {'file_number': '_build_file_number_series', 'scan_rate': '_build_scan_rate', 'selector': '_build_selector_series'}

Series which should be constructed from other series by the specified method and cached the first time they are looked up

class ixdat.techniques.cv.CyclicVoltammogramDiff(*args, **kwargs)[source]
default_plotter

alias of CVDiffPlotter