Skip to main content

Natus/Nicolet/Nervus .e → EDF+

Logo

An open-source Python converter for Natus/Nicolet/Nervus .e EEG recordings to standard EDF+ format. It runs without vendor DLLs or MATLAB and can convert individual recordings or folders from the command line. Legacy .eeg support is experimental; see Limitations.

Note: Some reverse-engineered event labels are currently in Norwegian.

Quick Start

Install the latest release from PyPI. To run it once without installing it permanently:

uvx nicolet-e2edf --help
uvx nicolet-e2edf --in /path/to/recording.e --out ./edf_output

To install it as a persistent uv tool:

uv tool install nicolet-e2edf
nicolet-e2edf --in /path/to/recording.e --out ./edf_output

Or install it with pip:

python -m pip install nicolet-e2edf
nicolet-e2edf --in /path/to/recording.e --out ./edf_output

The input can also be a folder containing .e/.eeg files:

nicolet-e2edf --in ./my_eeg_folder --out ./edf_output

Install from source

For development, clone the repository and let uv create the project environment:

git clone https://github.com/haukurtg/e2edfconverter.git
cd e2edfconverter
uv sync
uv run nicolet-e2edf --help

Optional faster reads (0.4.0)

Conversion got faster in 0.4.0 without changing the output bytes. There is also an experimental reader that merges adjacent disk reads into bigger ones (capped at 8 MiB per read). It produces identical output but is off by default for now; turn it on if you want the extra speed:

NICOLET_E2EDF_COALESCE_READS=1 nicolet-e2edf \
    --in /path/to/recording.e --out ./edf_output

or from Python: read_nervus_data(path, header, coalesce_reads=True).

Interactive Mode

For a guided experience with menus and progress bars:

uvx --with rich nicolet-e2edf --ui

For a persistent installation, use python -m pip install "nicolet-e2edf[tui]" or uv tool install "nicolet-e2edf[tui]", then run nicolet-e2edf --ui.

TUI Screenshot

CLI Options

Option Description
--in Input .e/.eeg file or folder
--out Output directory for EDF files
--glob Filter pattern when input is a folder (e.g. recording_*)
--json-sidecar Also emit a .json with metadata (channels, events, etc.)
--split-by-segment Output one EDF per segment if the recording contains multiple segments
--vendor-style Suppress system events to better match vendor EDF exports
--resample-to Resample to a specific rate (Hz) (requires scipy)
--lowcut High-pass filter cutoff in Hz (requires scipy)
--highcut Low-pass filter cutoff in Hz (requires scipy)
--notch Notch filter for powerline noise, e.g. 50 or 60 Hz (requires scipy)
--ui Launch interactive terminal UI (requires rich)
--verbose Show detailed logging

Filtering example:

# Install the optional filtering dependency once
python -m pip install "nicolet-e2edf[filter]"

# Clinical defaults: 0.5–35 Hz bandpass + 50 Hz notch
nicolet-e2edf \
    --in ./data --out ./edf_output \
    --lowcut 0.5 --highcut 35 --notch 50

Vendor-style comparison example:

# Match vendor-style exports (split per segment + suppress system events)
nicolet-e2edf \
    --in /path/to/recording.e --out ./edf_output \
    --split-by-segment --vendor-style --json-sidecar

Viewing the Results

In a source checkout, the bundled viewer script shows your EDF in a double-banana montage:

uv run --isolated --with mne python inspect_edf.py ./edf_output/recording.edf

Note: When using the interactive TUI (--ui), the viewer is automatically launched with MNE in an isolated environment if needed. No manual installation required!

Options: --lowcut, --highcut, --notch, --snapshot out.png (for headless systems).

Filtering during conversion (--lowcut, --highcut, --notch) is lossy. In most cases, keep exports unfiltered and only use conversion-time filtering when you intentionally want a preprocessed output for direct downstream use (for example, an ML pipeline).

Limitations

  • Mixed sampling rates: default exports only dominant-rate channels; use --resample-to to include all "on" channels.
  • When --resample-to is used, channels are resampled to the requested integer EDF rate.
  • Events are written as EDF+ annotations
  • EVENTTYPEINFOGUID labels are reverse-engineered; unknown GUIDs may be exported as UNKNOWN.
  • .eeg support is currently not reliable; we need a larger .eeg dataset to implement and validate it properly.
  • Some .e recordings store only numeric channel IDs (e.g., 1..64). The numeric-channel fix and montage-recovery strategy (from v0.2.5) are mainly aimed at recovering channel names in atypical multi-channel EEG setups (32, 64, 128, etc.) using source montage derivations, fixed DERIVATION tables, and hidden montage catalogs.
  • The CLI supports folder input, but processes files serially. For large cohorts, it is usually more efficient to call the CLI from a small batch wrapper that runs multiple workers and tracks progress/errors.

Contributing

Contributions are welcome! If you're working on the EDF writer or want to understand the file format:

  • EDF+ Specification: A copy of the full EDF+ specification is included at docs/EDF+ specification.pdf. The official spec is also available at edfplus.info.
  • Tests: Run uv run pytest to verify EDF+ compliance. We use PyEDFlib as a strict validator.

Profiling And Regression Checks

Two helper scripts are included for speed work that must not change output:

  • tools/profile_conversion_stages.py
    • Runs an in-process conversion profile for one or more .e files.
    • Breaks runtime into rough stages such as header read, waveform read, EDF write, and JSON write.
  • tools/validate_regression_equivalence.py
    • Re-converts a regression corpus and compares the result against a known-good baseline.
    • Checks EDF byte equality plus exact equality of sidecar channels, events, and annotations (ignoring only the expected edf_file output path field).

Recommended workflow for performance changes:

  1. Profile on a small representative local corpus.
  2. Make the optimization.
  3. Run uv run pytest.
  4. Run the regression-equivalence validator before merging.

Acknowledgements

The MATLAB implementation of the Nervus/Nicolet file format in the FieldTrip toolbox provided the foundation for this Python port. Additional GUID, event and channel-ID handling was developed through reverse engineering.

Development was assisted by various coding models used through Cursor.

License

GPL-3.0 — see LICENSE.

This project adapts logic from the FieldTrip toolbox (GPL-3.0).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nicolet_e2edf-0.4.2.tar.gz (127.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nicolet_e2edf-0.4.2-py3-none-any.whl (123.9 kB view details)

Uploaded Python 3

File details

Details for the file nicolet_e2edf-0.4.2.tar.gz.

File metadata

  • Download URL: nicolet_e2edf-0.4.2.tar.gz
  • Upload date:
  • Size: 127.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nicolet_e2edf-0.4.2.tar.gz
Algorithm Hash digest
SHA256 57e4a10c79afb407efae0e2e6818416365569d3ae45e4bb55291082c64d6feed
MD5 e763990cf42d8353edd5e971b7aeb03b
BLAKE2b-256 21ba01ee7dc7306ea1547b010923a7c0b03ed3226e84bf7dc97acbff10c5cca4

See more details on using hashes here.

Provenance

The following attestation bundles were made for nicolet_e2edf-0.4.2.tar.gz:

Publisher: publish-pypi.yml on haukurtg/e2edfconverter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nicolet_e2edf-0.4.2-py3-none-any.whl.

File metadata

  • Download URL: nicolet_e2edf-0.4.2-py3-none-any.whl
  • Upload date:
  • Size: 123.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nicolet_e2edf-0.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a80b9a2fdee69bf3aea180d726bb385db5844075307efd4e20005be917b8198b
MD5 69f6d4392360ab7864c8ac2e2c571b87
BLAKE2b-256 076cb9cfa156138bb32738d92878041db2204c7103bb5b574cb990d45ddb138f

See more details on using hashes here.

Provenance

The following attestation bundles were made for nicolet_e2edf-0.4.2-py3-none-any.whl:

Publisher: publish-pypi.yml on haukurtg/e2edfconverter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.4.2 This release

2 files

0.4.1

2 files

0.4.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page