220 lines
6.1 KiB
Rust
220 lines
6.1 KiB
Rust
//! # rtx-neuro-io
|
|
//!
|
|
//! File format readers and writers for neuroimaging data.
|
|
//!
|
|
//! ## Supported Formats
|
|
//!
|
|
//! ### EEG Formats
|
|
//! - **EDF/EDF+** - European Data Format (most common research format)
|
|
//! - **BDF** - BioSemi 24-bit variant
|
|
//! - **BrainVision** - .vhdr/.vmrk/.eeg files
|
|
//! - **EGI** - Electrical Geodesics (.raw, .mff)
|
|
//!
|
|
//! ### MEG Formats
|
|
//! - **FIF** - Elekta/Neuromag format
|
|
//! - **CTF** - CTF MEG Systems (.ds directories)
|
|
//! - **BTi/4D** - 4D-Neuroimaging/BTi systems
|
|
//! - **KIT** - Yokogawa/KIT/Ricoh systems (.con, .sqd)
|
|
//!
|
|
//! ### Dataset Formats
|
|
//! - **BIDS** - Brain Imaging Data Structure (directory-based)
|
|
//!
|
|
//! ## Usage
|
|
//!
|
|
//! ```rust,ignore
|
|
//! use rtx_neuro_io::edf::EdfReader;
|
|
//! use rtx_neuro_io::fif::FifReader;
|
|
//! use rtx_neuro_io::ctf::CtfReader;
|
|
//! use rtx_neuro_io::bti::BtiReader;
|
|
//! use rtx_neuro_io::kit::KitReader;
|
|
//! use rtx_neuro_io::egi::EgiReader;
|
|
//!
|
|
//! // Read EDF file
|
|
//! let reader = EdfReader::open("recording.edf")?;
|
|
//! let data = reader.read_data(0.0, 10.0)?; // Read 10 seconds
|
|
//!
|
|
//! // Read FIF file (Elekta/Neuromag MEG)
|
|
//! let reader = FifReader::open("sample_raw.fif")?;
|
|
//! let data = reader.read_data(0.0, 10.0)?;
|
|
//!
|
|
//! // Read CTF dataset (directory-based)
|
|
//! let reader = CtfReader::open("experiment.ds")?;
|
|
//! let data = reader.read_data(0.0, 10.0)?;
|
|
//!
|
|
//! // Read 4D-Neuroimaging/BTi data
|
|
//! let reader = BtiReader::open("subject_data")?;
|
|
//! let data = reader.read_data(0.0, 10.0)?;
|
|
//!
|
|
//! // Read Yokogawa/KIT data
|
|
//! let reader = KitReader::open("recording.con")?;
|
|
//! let data = reader.read_data(0.0, 10.0)?;
|
|
//!
|
|
//! // Read EGI data
|
|
//! let reader = EgiReader::open("recording.raw")?;
|
|
//! let data = reader.read_data(0.0, 10.0)?;
|
|
//!
|
|
//! // Open BIDS dataset
|
|
//! use rtx_neuro_io::bids::BidsDataset;
|
|
//! let dataset = BidsDataset::open("my_bids_dataset")?;
|
|
//! println!("Dataset: {}", dataset.name());
|
|
//! for subject in dataset.subject_labels() {
|
|
//! println!(" Subject: {}", subject);
|
|
//! }
|
|
//! ```
|
|
|
|
#![warn(missing_docs)]
|
|
|
|
pub mod bids;
|
|
pub mod brainvision;
|
|
pub mod bti;
|
|
pub mod ctf;
|
|
pub mod edf;
|
|
pub mod egi;
|
|
pub mod fif;
|
|
pub mod kit;
|
|
|
|
// Re-export main types
|
|
pub use bids::{
|
|
BidsDataset, BidsFile, BidsSession, BidsSubject, DatasetDescription, FileEntities,
|
|
is_bids_dataset, parse_bids_filename,
|
|
};
|
|
pub use brainvision::BrainVisionReader;
|
|
pub use bti::{BtiChannel, BtiChannelKind, BtiConfig, BtiReader};
|
|
pub use ctf::{CtfChannel, CtfChannelKind, CtfReader, Res4Header};
|
|
pub use edf::{EdfHeader, EdfReader};
|
|
pub use egi::{EgiChannel, EgiChannelKind, EgiFormat, EgiHeader, EgiReader};
|
|
pub use fif::{FifChannel, FifInfo, FifReader};
|
|
pub use kit::{KitChannel, KitChannelKind, KitHeader, KitReader};
|
|
|
|
use std::path::Path;
|
|
|
|
/// Error types for I/O operations
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum IoError {
|
|
/// File I/O error
|
|
#[error("File I/O error: {0}")]
|
|
Io(#[from] std::io::Error),
|
|
|
|
/// Invalid file format
|
|
#[error("Invalid file format: {0}")]
|
|
InvalidFormat(String),
|
|
|
|
/// Unsupported format version
|
|
#[error("Unsupported format version: {0}")]
|
|
UnsupportedVersion(String),
|
|
|
|
/// Header parsing error
|
|
#[error("Header parsing error: {0}")]
|
|
HeaderParse(String),
|
|
|
|
/// Data parsing error
|
|
#[error("Data parsing error: {0}")]
|
|
DataParse(String),
|
|
|
|
/// File not found
|
|
#[error("File not found: {0}")]
|
|
FileNotFound(String),
|
|
|
|
/// Channel not found
|
|
#[error("Channel not found: {0}")]
|
|
ChannelNotFound(String),
|
|
}
|
|
|
|
/// Result type for I/O operations
|
|
pub type IoResult<T> = Result<T, IoError>;
|
|
|
|
/// Trait for file format readers
|
|
pub trait NeuroReader {
|
|
/// Read file header/metadata
|
|
fn read_header(&mut self) -> IoResult<()>;
|
|
|
|
/// Get sampling frequency in Hz
|
|
fn sfreq(&self) -> f64;
|
|
|
|
/// Get number of channels
|
|
fn n_channels(&self) -> usize;
|
|
|
|
/// Get total number of samples per channel
|
|
fn n_samples(&self) -> usize;
|
|
|
|
/// Get channel names
|
|
fn channel_names(&self) -> Vec<String>;
|
|
|
|
/// Read raw data for specified time range
|
|
/// Returns data as [n_channels x n_samples]
|
|
fn read_raw_data(&mut self, tmin: f64, tmax: f64) -> IoResult<Vec<f64>>;
|
|
|
|
/// Read all data
|
|
fn read_all_data(&mut self) -> IoResult<Vec<f64>> {
|
|
let duration = self.n_samples() as f64 / self.sfreq();
|
|
self.read_raw_data(0.0, duration)
|
|
}
|
|
}
|
|
|
|
/// Detect file format from path
|
|
pub fn detect_format(path: impl AsRef<Path>) -> Option<FileFormat> {
|
|
let path = path.as_ref();
|
|
|
|
// Check for directory-based formats
|
|
if path.is_dir() {
|
|
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
|
if name.ends_with(".ds") {
|
|
return Some(FileFormat::Ctf);
|
|
}
|
|
if name.ends_with(".mff") {
|
|
return Some(FileFormat::Egi);
|
|
}
|
|
// Check for BTi directory (contains config file)
|
|
let config_path = path.join("config");
|
|
if config_path.exists() {
|
|
return Some(FileFormat::Bti);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check file extension
|
|
let ext = path.extension()?.to_str()?.to_lowercase();
|
|
|
|
match ext.as_str() {
|
|
"edf" => Some(FileFormat::Edf),
|
|
"bdf" => Some(FileFormat::Bdf),
|
|
"vhdr" => Some(FileFormat::BrainVision),
|
|
"set" => Some(FileFormat::EegLab),
|
|
"fif" => Some(FileFormat::Fif),
|
|
"ds" => Some(FileFormat::Ctf),
|
|
"cnt" => Some(FileFormat::Neuroscan),
|
|
"nwb" => Some(FileFormat::Nwb),
|
|
"con" | "sqd" => Some(FileFormat::Kit),
|
|
"raw" => Some(FileFormat::Egi),
|
|
"mff" => Some(FileFormat::Egi),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
/// Supported file formats
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum FileFormat {
|
|
/// EDF (European Data Format)
|
|
Edf,
|
|
/// BDF (BioSemi 24-bit)
|
|
Bdf,
|
|
/// BrainVision (.vhdr/.vmrk/.eeg)
|
|
BrainVision,
|
|
/// EEGLAB (.set)
|
|
EegLab,
|
|
/// Elekta/Neuromag FIF
|
|
Fif,
|
|
/// CTF MEG
|
|
Ctf,
|
|
/// 4D-Neuroimaging/BTi MEG
|
|
Bti,
|
|
/// Yokogawa/KIT/Ricoh MEG
|
|
Kit,
|
|
/// EGI (.raw, .mff)
|
|
Egi,
|
|
/// Neuroscan (.cnt)
|
|
Neuroscan,
|
|
/// Neurodata Without Borders
|
|
Nwb,
|
|
}
|