To get cyclic voltammetry data out of a potentiostat software package like Metrohm’s NOVA, a researcher opens the Data Export Tool and wires each measured signal to an output column by hand, one measurement at a time, a step the current NOVA manual documents with a choice of five column delimiters and two decimal separators.
There’s no shared file format underneath much of this: NOVA alone offers a choice of four output formats from its export command, ASCII, Excel, ZView, or RelaxIS, before the delimiter and decimal-separator questions even come up; Autolab’s ASCII path writes semicolon- or tab-delimited tables. CH Instruments’ native format is binary by default; its software saves or converts to plain text or CSV as an opt-in setting or a batch command. PalmSens’ PSTrace saves working sessions as .pssession (JSON) but exports curves to CSV, Excel, or OriginLab with one click.
Every vendor can get you to a delimited file eventually, by a different route, in a different layout, and none of them agree on how to record which sample or concentration a scan belongs to.
Biosensor (PyPI, GitHub) is a free, open-source Python package built for that situation: point it at a folder of mixed exports, and it detects each file’s format from its contents, converts everything into one tidy dataframe or CSV, and attaches a quality check to every parse. Here’s how it works today.
Why a cross-vendor parser is needed
The same voltage-current sweep leaves three instruments in three encodings, each designed for its own desktop software: NOVA for Autolab, PSTrace for PalmSens, and the CHI suite for CH Instruments. Vendors keep improving their own ends of the pipeline:
- Metrohm’s newest instrument, VIONIC, runs on INTELLO, which exports automatically in multiple standard formats.
- PalmSens publishes developer SDKs for its session format, and its PSTrace manual documents one-click export to CSV, Excel, and OriginLab.
- CH Instruments’ current 600F series still saves binary by default; its File menu can save text alongside the binary file or batch-convert existing files afterward, and their manual recommends keeping the binary copy since it’s the only format that retains every acquisition parameter.
Each improvement applies within one product line, though, and none of the three share a column layout or a metadata convention.
Community fixes tend to be scoped the same way: single-author converters like PySimpleEChem cover the formats their maintainers use, and JCAMP-DX, the shared format the Chemotion notebook accepts, comes from spectroscopy and still needs a second parse before pandas sees a number. Combining data across brands remains the researcher’s job. Biosensor handles that step.
| Instrument | Native software | Default container | Delimiter / decimal | Sample + concentration |
|---|---|---|---|---|
| CH Instruments | CHI suite | Plain text (binary is native; text/CSV is exported) | Comma | Not native |
| Metrohm Autolab | NOVA | Text / CSV (one of four export formats) | Semicolon or tab; decimal comma on European locales | Not native |
| PalmSens | PSTrace | .pssession (JSON); exports to CSV, Excel, or Origin | n/a | Partial |
Deeper file detection for mixed exports
Biosensor ships four readers: CH Instruments text exports, Metrohm Nova text/CSV exports, PalmSens .pssession sessions (best-effort), and generic delimited CSV, including files with metadata lines before the header and headerless two-column numeric files.
Each reader identifies its format from the file’s content, its signature and header structure, so a Nova table renamed to .txt or a CHI export with no extension should still parse correctly.
Files are treated as untrusted input: per-file byte and row limits bound the parsing cost, no reader executes macros or scripts, and any parse failure degrades to a per-file error instead of a crash.
A batch load never aborts because one file is malformed; the bad file is recorded with an error category (unsupported, parse, too large, corrupt, or unexpected) while the rest of the folder loads.
A single output schema
Every reader emits the same Measurement: potential, current, scan rate, cycle number, technique, sample ID, analyte name and concentration, plus a flexible parameter dict for technique-specific values like SWV frequency or DPV pulse width. The immunoassay metadata that vendor formats don’t standardize (which sample, which analyte, what concentration) is accounted for in the schema.
from biosensor import batch_load
batch = batch_load("2026-08-05-run/") # CH Instruments, Nova, PalmSens, CSV
df = batch.to_dataframe() # one tidy table, one row per point
df.to_csv("run.csv")
batch.qc_dataframe() # ok / flagged / failed, per file
The dataframe is long-form, one row per data point, so it drops straight into pandas groupbys, Plotly, or an sklearn pipeline. Analysis frameworks for electrochemical immunoassays, like pyEIA (full text here), can also begin from a structured table of this kind.
Sanity checks for quality control
A file can parse without error and still be wrong: swap potential and current and you get a plausible curve. Every parse therefore runs through a curve-shape heuristic, and the verdict is stored with the file as a separate QC record.
| Status | What triggers it |
|---|---|
| failed | Fewer than five points*; NaN or infinite values; a constant potential or current column, the signature of a wrong column mapping |
| flagged | A potential range wider than 5 V; a sweep with no return cycle (technically, that flag only fires when the technique is known and isn’t a linear sweep); no peak or inflection in the current trace |
| ok | None of the above |
The check catches silent parse failures, not assay quality, and a manual override is always available.
* Why 5 points? → It’s a heuristic floor, not an electrochemistry constant. The QC check decides “does this look like a real voltammogram?” by counting sign changes in the current trace (a curve should rise then fall → which means at least one reversal) and checking the potential sweeps forward and back. Those shape tests need a handful of points to mean anything; with 3–4 points you can’t tell a genuine peak from noise or a straight line. So below 5, rather than green-light something it can’t verify, it fails outright. A real CV scan has hundreds of points, so a sub-5-point file is almost certainly a truncated or broken parse.
Local viewer for review and export
The repository ships a local viewer (Flask, one double-click launcher per platform) that opens in the browser with three panes: a file list with live filter and ok/flagged/failed tabs, the centre pane with Curve, DataFrame, and Overlay tabs (Overlay layers one sample’s curves across its concentration series, colour-graded low to high), and the parse record with instrument metadata and the sample-to-concentration mapping.
When a file parses wrong, you correct the column mapping in place with a live preview before applying, override the quality flag if the heuristic misjudged, and export any file or the whole batch as CSV. Everything is vendored, so the viewer runs fully offline; it’s local, single-user, and in-memory by design.
pip install biosensor from PyPI; MIT-licensed and open source.
