HivePaaS
An open-source, self-hosted PaaS on Docker Swarm. Deploy apps, databases and functions from one VPS to a whole cluster, with SSL, backups and autoscaling built in.
Read and write MEF 3.0 (Multiscale Electrophysiology Format) recordings such as EEG, iEEG and ECG from Python, MATLAB and C++, compatible with meflib, pymef and mef_tools.
Developer toolsC++ · PythonGitHub @bnelairOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Read and write MEF 3.0 (Multiscale Electrophysiology Format) EEG, iEEG and ECG recordings from Python, MATLAB and C++. One C++ core, compatible with meflib, pymef and mef_tools.
Taken from the repository README
Loading the full README.
Read the full README ↗Read and write MEF 3.0 (Multiscale Electrophysiology Format) files from Python, MATLAB and C++. MEF 3.0 is a compressed, optionally encrypted file format for long electrophysiology recordings: mainly EEG, intracranial EEG (iEEG) and ECG, but it suits any regularly sampled signal, such as EMG, other biosignals or sensor data. One C++ core does the work, so every language reads and writes the same files the same way. Sessions written by mef3io open in the established MEF 3.0 tools listed below, and sessions written by those tools open in mef3io.
Documentation: https://bnelair.github.io/mef3io/
mef3io grew out of an earlier stack of MEF libraries and stays compatible with it: files written by either open in the other. MEF 3.0 support is maintained here, in mef3io, as open source (Apache-2.0).
meflib.h,
is titled "Specification for Multiscale Electrophysiology Format (MEF)
version 3.0". The format's design is described in Brinkmann et al.,
Large-scale electrophysiology: acquisition, compression, encryption, and
storage of big data, J Neurosci Methods 180(1):185-192, 2009,
doi:10.1016/j.jneumeth.2009.03.022.mef-tools): high-level Python
reading and writing built on pymef. mef3io stands in for it:
from mef3io import MefReader, MefWriter.mef3io is an independent implementation of the specification, tested against meflib, pymef and mef_tools. New to the format? See MEF 3.0 for students.
pip install mef3io
Prebuilt wheels for Linux, macOS and Windows (Python 3.10+); numpy is the only
dependency. For MATLAB, download mef3io-matlab-vX.Y.Z.zip from the
latest release and
addpath it, or build the MEX yourself. For C++, add core/ to your CMake
project. Details for all three: Install.
import numpy as np
import mef3io
fs = 256.0
start = 1_700_000_000_000_000 # microseconds since 1970 (uUTC)
signal = np.random.randn(60 * int(fs)) # one minute
signal[1000:1500] = np.nan # a gap: NaN is stored as missing data
with mef3io.Writer("session.mefd", overwrite=True, units="uV") as w:
w.write("eeg1", signal, start, fs=fs)
w.write("eeg2", signal[::-1].copy(), start, fs=fs)
w.write_annotations([{"time": start, "text": "recording start"}], channel="eeg1")
# leaving the block waits until everything is on disk (w.flush() does it mid-way);
# w.write_many([...], 2-D array, start, fs) writes many channels in one call:
# https://bnelair.github.io/mef3io/long_recordings/#when-is-my-data-on-disk
with mef3io.Reader("session.mefd") as r:
print(r.channels) # ['eeg1', 'eeg2']
x = r.read("eeg1", start, start + 10_000_000) # first 10 s, float64, gaps = NaN
print(r.segments("eeg1")) # what data is where
X = r.read(["eeg1", "eeg2"], start, start + 10_000_000) # a list: 2-D, one row per channel
env = r.block_envelope("eeg1") # per-block min/max from the index: no decoding
print(r.records("eeg1")) # annotations
The same session in MATLAB:
r = mef3io.Reader('session.mefd');
x = r.read('eeg1');
More: the Python, MATLAB and C++ guides, runnable examples, and short how-to pages such as converting EDF, EDF+ or BDF to MEF 3.0.
NaN on the sampling grid, never silently stitched together;
read_raw returns the raw integer samples with a validity mask.Writer kept open, each append costs time in proportion
to the new data, not to the recording so far. If a write is interrupted,
the session can be checked and recovered. Many channels can be written in
one call (write_many), in parallel, with one wait for the disk — see Long recordings and
Validating and repairing.from mef3io import MefReader, MefWriter runs code written for the
legacy mef_tools package with only the import changed.mef3io.inspect(path) (or
python -m mef3io inspect) describes a session — channels, segments,
gaps, annotations, encryption, what identifying fields it holds — without
reading any samples, and long reads and operations can report progress and
be cancelled from another thread (Python and C++).mef3io.anonymize_session writes a de-identified copy of a session:
names, ID, location, descriptions and annotation text removed, and the
samples copied unchanged. By default it keeps the real dates and times;
with a shift, every date and time is moved by the same amount (so events
still line up with the signal). Channels can be left out, and the copy
can be unencrypted or protected with new passwords.
mef3io.anonymize.check reports everything that would stop a copy before
anything is written, and every copy is verified against its source (no
original name left anywhere, and with a shift no original date) before it
is saved. The original is
never changed. Python and C++; see
De-identification.2.0 removes the per-call n_threads argument (set r.n_threads) and the
Writer(durability=) option (use flush() or wait_for_disk=True), and
anonymize_session keeps dates unless you pass a shift. The full list, with
what to do for each, is in the
2.0.0 release notes.
Sessions written by mef3io 1.1.2 and earlier read correctly in mef3io and
pymef, but declare some buffer sizes as 0, which can crash meflib-based
readers. Opening one warns once. Appending with a current version repairs the
segment it extends; mef3io.repair_session fixes the rest in place — see
Validating and repairing.
Changes in every version, and what an upgrade asks of you, are listed in the
release notes.
.vidd) are out of scope; a session's video folders are
skipped..mefd.tar sessions are a mef3io addition, not part of
MEF 3.0, so meflib, pymef and mef_tools cannot open them directly. They
are plain uncompressed tar files, so they can always be unpacked:
mef3io.extract_session, tar -xf (built into Windows 10 and later,
macOS and Linux) or the free 7-Zip on Windows. The unpacked .mefd folder
works with the legacy tools.Note, SyLg and EDFA can be written with their text.mef3io.anonymize_session (Python and C++, not MATLAB), with a shift to
hide the dates. It keeps channel
names and does not change the signal itself, and with annotation text kept
it removes only the names it knows — see
.Bug reports, feature requests and questions go to issues. To build and test from source, see CONTRIBUTING.md; the on-disk format reference and the design are on the documentation site. Report vulnerabilities privately as described in SECURITY.md.
core/ C++ library (the format, read, write, validation) + Catch2 tests
bindings/ Python extension (nanobind)
python/ the mef3io Python package
matlab/ MEX gateway over the C ABI + the +mef3io MATLAB classes
examples/ runnable scripts
tests/ pytest suites, cross-checked against pymef / mef_tools
benchmarks/ performance comparisons
docs/ documentation site source
If you use mef3io in published work, please cite it via CITATION.cff. Licensed under Apache 2.0. Maintained by Filip Mivalt, Bioelectronics Neurophysiology and Engineering Laboratory (BNEL) at Mayo Clinic.
mef3io: Filip Mivalt (maintainer), Vladimir Sladky, Václav Křemen.
Past tools contributors: Bruno Aristimunha, Mark R. Bower, Benjamin H. Brinkmann, Clemens Brunner, Jan Cimbálník, Daniel P. Crepeau, Richard Jie Cui, Arnaud Delorme, Dora Hermes, Václav Křemen, Eric Larson, Filip Mivalt, Vladimir Sladky, Matt Stead, Keith A. Stengel, Max van den Boom, Vince Vasoli, Gregory A. Worrell and others. We thank them all. The past tools are listed above and in CONTRIBUTORS.md.
This project follows a code of conduct.
Reader can run from several
threads at once (a Writer is not for sharing). One n_threads count per
object covers opening, file access and decoding, so a session on a network
share opens in parallel; see
Threads.mef3io.transform_session writes a
copy with chosen channels, new passwords (or none), a new name and edited
subject details or descriptions, and can keep only a time window
(time_range=) or leave every annotation out (records="drop"). Every
time and sample is copied as stored, and the copy is checked against its
source before it is saved. Python and C++; see
Modified copies.mef3io.merge_sessions joins two or
more recordings: parts of one stay, recordings that take turns, or
different amplifiers. One call can also trim each recording to its own
time range, make the result anonymous and use several threads
(n_threads=). Overlapping data is refused before anything is written, and
the result is checked against every source. Different units or conversion
factors in one channel are merged with a warning, not refused. See
Merging recordings.
To read several recordings as one without writing anything,
mef3io.MultiReader([...]) is a drop-in for Reader (Python).mef3io.rename_session changes all of them as one operation that a crash
cannot leave half-done and that can be undone; mef3io.name_drift tells
whether they agree, and mef3io.time_range gives a session's first and
last sample time for ordering many sessions. Python and C++; see the
Python guide..mefd.tar and read in place, without unpacking..mefd.tar archives and recovers interrupted writes. Inspecting,
validating and repairing, cancelling and progress, de-identification,
modified copies, cut, merge and renaming are in Python and C++ only.backend="pure" raises); the
wheels carry the compiled core.