Metadata-Version: 2.4
Name: readmanager
Version: 1.4.0
Summary: Read, write and convert OpenBCI signal recordings (.raw/.xml/.tag)
Author: Faculty of Physics, University of Warsaw
Author-email: BrainTech <admin@braintech.pl>
License-Expression: GPL-3.0-or-later
Keywords: bci,eeg,obci,signal,readmanager
Classifier: Development Status :: 4 - Beta
Classifier: Natural Language :: English
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Environment :: Console
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.24
Provides-Extra: mne
Requires-Dist: mne>=1.5; extra == "mne"
Provides-Extra: balance
Requires-Dist: scipy; extra == "balance"
Requires-Dist: matplotlib; extra == "balance"
Provides-Extra: all
Requires-Dist: readmanager[balance,mne]; extra == "all"
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: pytest-timeout; extra == "test"
Requires-Dist: readmanager[all]; extra == "test"

# readmanager

Read, write and convert [OBCI](https://gitlab.com/fuw_software/obci) signal
recordings stored in the OBCI file format (`.raw` / `.xml` / `.tag`).

## Installation

```bash
pip install readmanager            # core (numpy only)
pip install readmanager[mne]       # + MNE-Python conversion
pip install readmanager[balance]   # + Wii Balance Board analysis (scipy)
pip install readmanager[all]       # everything
```

Requires Python 3.10+.

## Quick start

```python
from obci_readmanager.signal_processing.read_manager import ReadManager

# Open a recording (three files: .raw, .xml, .tag)
mgr = ReadManager(
    "recording.obci.xml",
    "recording.obci.raw",
    "recording.obci.tag",
)

# Access signal parameters
print(mgr.get_param("sampling_frequency"))
print(mgr.get_param("channels_names"))

# Get all samples as a numpy array (channels x samples)
samples = mgr.get_samples()

# Get samples for a single channel
fp1 = mgr.get_channel_samples("Fp1")

# Get samples in microvolts (applies gain and offset calibration)
uv = mgr.get_microvolt_samples()

# Iterate over tags (event markers)
for tag in mgr.iter_tags():
    print(tag["name"], tag["start_timestamp"])
```

## Smart tags

Smart tags extract signal segments aligned to event markers:

```python
from obci_readmanager.signal_processing.smart_tags_manager import SmartTagsManager
from obci_readmanager.signal_processing.tags.smart_tag_definition import SmartTagDurationDefinition

# Define: 1 second of signal after each "stimulus" tag
tag_def = SmartTagDurationDefinition(
    start_tag_name="stimulus",
    start_offset=0.0,
    end_offset=0.0,
    duration=1.0,
)

smart_mgr = SmartTagsManager(
    tag_def,
    "recording.obci.xml",
    "recording.obci.raw",
    "recording.obci.tag",
)

for smart_tag in smart_mgr.iter_smart_tags():
    data = smart_tag.get_samples()  # channels x samples for this epoch
    print(data.shape)
```

## MNE-Python conversion

```python
# ReadManager -> MNE Raw
raw_mne = mgr.get_mne_raw()

# MNE Raw -> ReadManager
mgr2 = ReadManager.from_mne(raw_mne)

# Smart tags -> MNE Epochs
epochs = smart_mgr.get_mne_epochs()
```

### Channel type heuristic

When converting to MNE, `get_mne_raw()` and friends need to assign an
MNE channel type (`'eeg'`, `'eog'`, `'emg'`, `'ecg'`, `'bio'`, `'stim'`,
`'misc'`) to every channel. If you pass an explicit `channel_types` list,
it's used as-is; otherwise readmanager applies a name-based heuristic
via `chtype_heuristic(name)` from the `mne_utils` submodule.

The heuristic recognises, in order of priority:

| Rule | Example inputs | Returns |
|---|---|---|
| Substring `eog` | `EOG Left Horiz`, `VEOG`, `EOG Fp1-M2` | `eog` |
| Substring `emg` | `EMG Chin1`, `EMG Ant Tibia-0` | `emg` |
| Substring `ecg` / `ekg` | `ECG ECGI`, `EKG_lead1` | `ecg` |
| Substring `resp` / `sao2` / `spo2` | `Resp Thermistor`, `SaO2 SaO2` | `bio` |
| Substring `stim` / `trig` / `marker` / `status` / `sync` or prefix `sti ` | `STIM`, `Trigger`, `STI 014`, `STATUS` | `stim` |
| Tokenised 10-05 position lookup | `Fp1`, `C3`, `EEG F3-CLE`, `Fp1-M2`, `F3-CAR` | `eeg` |
| Fall-through | anything else (`Channel_42`, `Aux1`, `Photo`) | `misc` |

The 10-05 position check tokenises the channel name on any
non-alphanumeric boundary and matches each token against MNE's
`standard_1005` montage position set. This catches prefixed/suffixed
variants common in EDF polysomnography recordings (`EEG F3-CLE`,
`EEG Fp1-M2`) without false-positives on short position names
embedded in unrelated words (e.g. `audio1`, `Data1`, `misc3`).

Non-EEG substring rules take priority over the position lookup, so
`EOG Fp1-M2` (an EOG reference channel using Fp1/M2 as the reference
montage) is correctly typed as `eog` rather than `eeg`.

If your recording has channels the heuristic doesn't classify to your
taste, pass an explicit list:

```python
raw = mgr.get_mne_raw(channel_types=["eeg"] * 32 + ["ecg", "stim"])
```

See the `chtype_heuristic` docstring for the full decision order and
edge cases, and `test/signal_processing/test_chtype_heuristic.py` for
the complete parametrised test matrix.

## OBCI file format

An OBCI recording consists of three files:

| File | Content |
|------|---------|
| `.obci.raw` | Binary signal data (channels interleaved, float64 by default) |
| `.obci.xml` | Recording metadata: channel names, sampling frequency, gains, offsets |
| `.obci.tag` | Event markers in XML format (name, timestamp, duration, description) |

## Part of the OBCI ecosystem

`readmanager` is used by [OBCI](https://gitlab.com/fuw_software/obci) for
signal file replay and post-recording correction.  Related packages:

- [obci-server](https://gitlab.com/fuw_software/obci) — EEG acquisition server (depends on readmanager)
- [obci-desktop](https://gitlab.com/fuw_software/obci-desktop) — desktop launcher and LSL streaming
- [obci-psychopy](https://gitlab.com/fuw_software/obci-psychopy) — PsychoPy tag integration
- [SVAROG4](https://gitlab.com/fuw_software/svarog4) — Java signal viewer/recorder

## License

GNU General Public License v3 or later (GPLv3+).

Originally developed by [BrainTech](http://www.braintech.pl) and the
Faculty of Physics, University of Warsaw.
