Skip to content

Commit 470d864

Browse files
authored
Merge pull request #45 from bcliang/square-wave-voltammetry
Impl: support for Square Wave Voltammetry experiments
2 parents ed0c932 + a762b64 commit 470d864

File tree

9 files changed

+266
-22
lines changed

9 files changed

+266
-22
lines changed

.coveragerc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ source =
55

66
omit =
77
gamry_parser/__init__.py
8-
gamry_praser/version.py
8+
gamry_parser/version.py
99

1010
[report]
1111
exclude_lines =

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,24 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1313
### Added
1414
-
1515

16+
## [0.4.6] - 2021-05-07
17+
18+
### Fixed
19+
- [ed0c932](https://github.com/bcliang/gamry-parser/commit/ed0c93208f5a5ce3b62d5c619e3fd6aa34158b35) Fix: Static typing for class methods, resolve pandas futurewarning
20+
21+
### Changed
22+
-
23+
24+
### Added
25+
- [#45](https://github.com/bcliang/gamry-parser/pull/45) Impl: support for Square Wave Voltammetry experiments
26+
1627
## [0.4.5] - 2021-05-07
1728

1829
### Fixed
1930
-
2031

2132
### Changed
22-
- [#40](https://github.com/bcliang/gamry-parser/pull/40) Change: GamryParser to_timestamp param #40
33+
- [#40](https://github.com/bcliang/gamry-parser/pull/40) Change: GamryParser to_timestamp param
2334
- [#41](https://github.com/bcliang/gamry-parser/pull/41) Use tox as test runner
2435

2536
### Added

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,16 @@ print(ca.get_curve_data())
7777

7878
#### Demos
7979

80+
A simple demonstration is provided in `usage.py`.
81+
82+
`python usage.py`
83+
8084
ipython notebook demonstration scripts are included in the `demo` folder.
8185

8286
- `notebook_gamry_parser.ipynb`: Simple example loading data from ChronoA experiment output. Instead of `gamry_parser.GamryParser()`, the parser could be instantiated with `gamry_parser.ChronoAmperometry()`
8387
- `notebook_cyclicvoltammetry.ipynb`: Example loading data from a CV (cyclic voltammetry) experiment output. Uses the `gamry_parser.CyclicVoltammetry()` subclass.
88+
- `notebook_cyclicvoltammetry_peakdetect.ipynb`: Another example that demonstrates loading CV data and detecting peaks in the data using `scipy.signal.find_peaks()`
89+
- `notebook_potentiostatic_eis.ipynb`: Example loading data from an EIS (electrochemical impedance spectroscopy) experiment. Uses the `gamry_parser.Impedance()` subclass.
8490

8591
#### Additional Examples
8692

gamry_parser/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
from .cv import CyclicVoltammetry
55
from .eispot import Impedance
66
from .ocp import OpenCircuitPotential
7+
from .squarewave import SquareWaveVoltammetry
78
from .vfp600 import VFP600

gamry_parser/gamryparser.py

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,23 @@
99
class GamryParser:
1010
"""Load experiment data generated in Gamry EXPLAIN format."""
1111

12-
fname = None
13-
to_timestamp = False
12+
fname: str = None
13+
to_timestamp: bool = False
14+
loaded: bool = False
1415

15-
def __init__(self, filename=None, to_timestamp=None):
16+
header_length: int = 0
17+
header: dict = None
18+
19+
curve_count: int = 0
20+
curves: list = []
21+
curve_units: dict = dict()
22+
23+
ocv_exists: bool = False
24+
ocv: pd.DataFrame = None
25+
26+
REQUIRED_UNITS: dict = dict(CV=dict(Vf="V vs. Ref.", Im="A"))
27+
28+
def __init__(self, filename: str = None, to_timestamp: bool = None):
1629
"""GamryParser.__init__
1730
1831
Args:
@@ -27,17 +40,22 @@ def __init__(self, filename=None, to_timestamp=None):
2740
self.to_timestamp = (
2841
to_timestamp if to_timestamp is not None else self.to_timestamp
2942
)
43+
self._reset_props()
44+
45+
def _reset_props(self):
46+
"re-initialize parser properties"
47+
48+
self.loaded = False
49+
3050
self.header = dict()
3151
self.header_length = 0
32-
self.loaded = False
52+
3353
self.curves = []
3454
self.curve_count = 0
3555
self.curve_units = dict()
36-
self.ocv = None
56+
3757
self.ocv_exists = False
38-
self.REQUIRED_UNITS = {
39-
"CV": {"Vf": "V vs. Ref.", "Im": "A"},
40-
}
58+
self.ocv = None
4159

4260
def load(self, filename: str = None, to_timestamp: bool = None):
4361
"""save experiment information to \"header\", then save curve data to \"curves\"
@@ -81,22 +99,22 @@ def _convert_T_to_Timestamp(self):
8199
for curve in self.curves:
82100
curve["T"] = start_time + pd.to_timedelta(curve["T"], "s")
83101

84-
def get_curve_count(self):
102+
def get_curve_count(self) -> int:
85103
"""return the number of loaded curves"""
86104
assert self.loaded, "DTA file not loaded. Run GamryParser.load()"
87105
return self.curve_count
88106

89-
def get_curve_indices(self):
107+
def get_curve_indices(self) -> tuple:
90108
"""return indices of curves (zero-based indexing)"""
91109
assert self.loaded, "DTA file not loaded. Run GamryParser.load()"
92110
return tuple(range(self.curve_count))
93111

94-
def get_curve_numbers(self):
112+
def get_curve_numbers(self) -> tuple:
95113
"""return Gamry curve numbers (one-based indexing, as in Gamry software)"""
96114
assert self.loaded, "DTA file not loaded. Run GamryParser.load()"
97115
return tuple(range(1, self.curve_count + 1))
98116

99-
def get_curve_data(self, curve: int = 0):
117+
def get_curve_data(self, curve: int = 0) -> pd.DataFrame:
100118
"""retrieve relevant experimental data
101119
102120
Args:
@@ -114,17 +132,17 @@ def get_curve_data(self, curve: int = 0):
114132
)
115133
return self.curves[curve]
116134

117-
def get_curves(self):
135+
def get_curves(self) -> list:
118136
"""return all loaded curves as a list of pandas DataFrames"""
119137
assert self.loaded, "DTA file not loaded. Run GamryParser.load()"
120138
return self.curves
121139

122-
def get_header(self):
140+
def get_header(self) -> list:
123141
"""return the experiment configuration dictionary"""
124142
assert self.loaded, "DTA file not loaded. Run GamryParser.load()"
125143
return self.header
126144

127-
def get_experiment_type(self):
145+
def get_experiment_type(self) -> str:
128146
"""retrieve the type of experiment that was loaded (TAG)
129147
130148
Args:
@@ -136,7 +154,7 @@ def get_experiment_type(self):
136154
assert self.loaded, "DTA file not loaded. Run GamryParser.load()"
137155
return self.header["TAG"]
138156

139-
def get_ocv_curve(self):
157+
def get_ocv_curve(self) -> pd.DataFrame:
140158
"""return the contents of OCVCURVE (if it exists). Deprecated in Framework version 7"""
141159
if self.ocv_exists:
142160
return self.ocv
@@ -150,7 +168,7 @@ def get_ocv_value(self):
150168
else:
151169
return None
152170

153-
def read_header(self):
171+
def read_header(self) -> list:
154172
"""helper function to grab data from the EXPLAIN file header, which contains the loaded experiment's configuration
155173
156174
Args:
@@ -216,7 +234,7 @@ def read_header(self):
216234

217235
return self.header, self.header_length
218236

219-
def read_curve_data(self, fid: int):
237+
def read_curve_data(self, fid: int) -> tuple:
220238
"""helper function to process an EXPLAIN Table
221239
222240
Args:
@@ -247,7 +265,7 @@ def read_curve_data(self, fid: int):
247265

248266
return keys, units, curve
249267

250-
def read_curves(self):
268+
def read_curves(self) -> list:
251269
"""helper function to iterate through curves in a dta file and save as individual dataframes
252270
253271
Args:

gamry_parser/squarewave.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import gamry_parser as parser
2+
3+
4+
class SquareWaveVoltammetry(parser.GamryParser):
5+
"""Load a Square Wave Voltammetry (SWV) experiment generated in Gamry EXPLAIN format."""
6+
7+
def load(self, filename: str = None, to_timestamp: bool = None):
8+
"""save experiment information to \"header\", then save curve data to \"curves\"
9+
10+
Args:
11+
filename (str, optional): file containing VFP600 data. defaults to None.
12+
Returns:
13+
None
14+
15+
"""
16+
super(SquareWaveVoltammetry, self).load(
17+
filename=filename, to_timestamp=to_timestamp
18+
)
19+
typecheck = self.header.get("TAG", None)
20+
assert (
21+
typecheck == "SQUARE_WAVE"
22+
), f"The input file does not contain data from a square wave voltammetry experiment (expected type SQUARE_WAVE, found {typecheck})."
23+
24+
@property
25+
def step_size(self):
26+
return self.header.get("STEPSIZE", None)
27+
28+
@property
29+
def pulse_size(self):
30+
return self.header.get("PULSESIZE", None)
31+
32+
@property
33+
def pulse_width(self):
34+
return self.header.get("PULSEON", None)
35+
36+
@property
37+
def frequency(self):
38+
return self.header.get("FREQUENCY", None)
39+
40+
@property
41+
def v_range(self):
42+
return (self.header.get("VINIT", 0), self.header.get("VFINAL", 0))
43+
44+
@property
45+
def cycles(self):
46+
return self.header.get("CYCLES", 0)
47+
48+
def get_curve_data(self, curve: int = 0):
49+
"""retrieve relevant SWV experimental data
50+
51+
Args:
52+
curve (int, optional): curve number to return. Defaults to 0.
53+
54+
Returns:
55+
pandas.DataFrame:
56+
- T: time, in seconds or Timestamp
57+
- Vfwd: forward potential, in V
58+
- Vrev: reverse potential, in V
59+
- Vstep: step potential, in V
60+
- Ifwd: peak forward current measurement, in A
61+
- Irev: peak reverse current measurement, in A
62+
- Idif: differential current measurement (pulse), in A
63+
64+
"""
65+
assert self.loaded, "DTA file not loaded. Run CyclicVoltammetry.load()"
66+
assert curve >= 0, "Invalid curve ({}). Indexing starts at 0".format(curve)
67+
assert (
68+
curve < self.curve_count
69+
), "Invalid curve ({}). File contains {} total curves.".format(
70+
curve, self.curve_count
71+
)
72+
df = self.curves[curve]
73+
74+
return df[["T", "Vfwd", "Vrev", "Vstep", "Ifwd", "Irev", "Idif"]]

gamry_parser/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.4.5"
1+
__version__ = "0.4.6"

tests/squarewave_data.dta

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
EXPLAIN
2+
TAG SQUARE_WAVE
3+
TITLE LABEL test-square-wave-experiment Test &Identifier
4+
DATE LABEL 12/31/2021 Date
5+
TIME LABEL 12:00:00 Time
6+
PSTAT PSTAT REF600-10000 Potentiostat
7+
NOTES NOTES 1 &Notes...
8+
9+
VINIT QUANT 0.00000E+000 Initial &E (V)
10+
VFINAL QUANT -5.00000E-001 Final &E (V)
11+
STEPSIZE QUANT 2.00000E+000 St&ep Size (mV)
12+
TIMERRES QUANT 3.33340E-005 &Timer Resolution
13+
FREQUENCY QUANT 1.00000E+002 &Frequency (Hz)
14+
PULSESIZE QUANT 2.50000E+001 Pulse Size &Epeak (mV)
15+
PULSEON QUANT 1.00000E-002 Pulse &Time (s)
16+
AREA QUANT 1.00000E+000 Electrode &Area (cm^2)
17+
IMODE SELECTOR 1 I/E Range &Mode
18+
IRANGE QUANT 1.00000E-002 &Max Current (mA)
19+
EQDELAY IQUANT 0 Equil. &Time (s)
20+
IRCOMP SELECTOR 0 IRCom&p
21+
PFCOR QUANT 5.00000E+001 PF Corr. (ohm)
22+
CYCLES IQUANT 251 C&ycles (#)
23+
ELECTRODETYPE SELECTOR 0 Electrode Type
24+
STRIPPING TOGGLE F Used for Stripping
25+
POLARITY TOGGLE F Signal Polarity
26+
LINEFREQ IQUANT 60 Line Frequency (Hz)
27+
SAMPLINGMODE SELECTOR 0 Sampling &Mode
28+
PSTATMODEL IQUANT 4 Pstat Model
29+
PSTATSECTION LABEL REF600-19054 Pstat Section
30+
PSTATSERIALNO LABEL 19054 Pstat Serial Number
31+
CTRLMODE IQUANT 1 Control Mode
32+
ELECTROMETER IQUANT 0 RE=0 or CS=1
33+
IESTAB IQUANT 2 I/E Stability
34+
CASPEED IQUANT 6 Control Amp Speed
35+
CONVENTION IQUANT 0 Current Convention
36+
ICHRANGE IQUANT 2 Ich Range
37+
ICHRANGEMODE TOGGLE F Ich Auto Range
38+
ICHOFFSETENABLE TOGGLE F Ich Offset Enable
39+
ICHOFFSET QUANT 0 Ich Offset (V)
40+
ICHFILTER IQUANT 2 Ich Filter
41+
VCHRANGE IQUANT 2 Vch Range
42+
VCHRANGEMODE TOGGLE F Vch Auto Range
43+
VCHOFFSETENABLE TOGGLE F Vch Offset Enable
44+
VCHOFFSET QUANT 0 Vch Offset (V)
45+
VCHFILTER IQUANT 1 Vch Filter
46+
ACHRANGE IQUANT 2 Ach Range
47+
ACHOFFSETENABLE TOGGLE F Ach Offset Enable
48+
ACHOFFSET QUANT 0 Ach Offset (V)
49+
ACHFILTER IQUANT 1 Ach Filter
50+
IERANGELOWERLIMIT IQUANT 1 I/E Range Lower Limit
51+
IERANGEMODE TOGGLE F I/E AutoRange
52+
IERANGE IQUANT 7 I/E Range
53+
POSFEEDENABLE TOGGLE F Positive Feedback IR Comp
54+
POSFEEDRESISTANCE QUANT 0 Positive Feedback Resistance (ohm)
55+
ACHSELECT IQUANT 4 Ach Select
56+
SENSECABLEID IQUANT 14 Sense Cable ID
57+
PWRCABLEID IQUANT 14 Power Cable ID
58+
DCCALDATE LABEL 9/10/2021 DC Calibration Date
59+
ACCALDATE LABEL 3/30/2021 AC Calibration Date
60+
THERMOSELECT IQUANT 1 Thermo Select
61+
FRAMEWORKVERSION LABEL 7.8.4 Framework Version
62+
INSTRUMENTVERSION LABEL 4.42 Instrument Version
63+
CURVE TABLE 251
64+
Pt T Vfwd Vrev Vstep Ifwd Irev Idif Sig Ach IERange Over Temp
65+
# s V V V A A A V V # bits deg C
66+
0 0.01 -2.55258E-002 3.75742E-002 6.02416E-003 1.95523E-007 -1.73274E-006 1.92826E-006 2.50000E-002 5.08394E-005 7 ........... -0.01
67+
1 0.02 -4.32258E-002 3.87742E-002 -2.22584E-003 8.75084E-008 -3.26548E-007 4.14056E-007 2.30000E-002 8.39387E-007 7 ........... -0.01
68+
2 0.03 -4.59258E-002 3.68742E-002 -4.52584E-003 -3.20547E-007 -8.85156E-008 -2.32032E-007 2.10000E-002 5.08394E-005 7 ........... -0.01
69+
3 0.04 -4.79258E-002 3.48742E-002 -6.52584E-003 -3.20547E-007 -4.65099E-008 -2.74037E-007 1.90000E-002 8.39387E-007 7 ........... -0.01
70+
4 0.05 -5.01258E-002 3.28742E-002 -8.62584E-003 -3.28548E-007 -4.50415E-009 -3.24044E-007 1.70000E-002 8.39387E-007 7 ........... -0.01
71+
5 0.06 -5.21258E-002 3.07742E-002 -1.06758E-002 -3.16547E-007 -1.45055E-008 -3.02041E-007 1.50000E-002 8.39387E-007 7 ........... -0.01
72+
6 0.07 -5.41258E-002 2.90742E-002 -1.25258E-002 -2.96544E-007 2.14994E-008 -3.18043E-007 1.30000E-002 8.39387E-007 7 ........... -0.01
73+
7 0.08 -5.59258E-002 2.66742E-002 -1.46258E-002 -3.28548E-007 3.75016E-008 -3.66050E-007 1.10000E-002 -4.91606E-005 7 ........... -0.01
74+
8 0.09 -5.79258E-002 2.46742E-002 -1.66258E-002 -3.08546E-007 3.95018E-008 -3.48047E-007 9.00000E-003 -4.91606E-005 7 ........... -0.01
75+
9 0.1 -6.00258E-002 2.26742E-002 -1.86758E-002 -3.34549E-007 6.75057E-008 -4.02055E-007 7.00000E-003 8.39387E-007 7 ........... -0.01
76+
EXPERIMENTABORTED TOGGLE T Experiment Aborted

0 commit comments

Comments
 (0)