Skip to content

ynoda714/AnyNMR-matlab

Repository files navigation

AnyNMR

🇯🇵 日本語

Open any NMR data.

Open in MATLAB Online

Read 3 vendors (Bruker / Varian / JEOL) · 1D + 2D · 10 nuclei.
Validated on 365+ real datasets, silent failure = 0. 1,485 tests PASS.
Runs instantly on MATLAB Desktop or MATLAB Online — no setup required.


Who is this for?

User type Typical task
Legacy data recovery Revive old Varian / JEOL archives — read .fid directories and .jdf files that current vendor software can no longer open
Batch processing Process hundreds of spectra with a single reproducible MATLAB script
Metabolomics / ML Multi-vendor feature extraction (binning) → PCA / PLS-DA with a unified API
qNMR / purity analysis Automated internal-standard quantification with full GUM uncertainty
Multi-vendor labs One nmrData struct and identical processing API across Bruker, Varian, and JEOL

Processing Pipeline

Processing Pipeline

All functions accept and return nmrData. Pipelines are composable.
See algorithm_guide.md for details.


Quick Start

Requirements: MATLAB R2025b, Signal Processing Toolbox, Curve Fitting Toolbox

% 1. Add path
addpath(genpath("src"));

% 2. Load data (choose your vendor)
nmrData = nmr.io.loadBruker("path/to/bruker/1");          % Bruker
nmrData = nmr.io.loadVarian("path/to/sample.fid");        % Varian
nmrData = nmr.io.loadJeol("path/to/sample.jdf");          % JEOL

% 3. 1D processing pipeline
nmrData = nmr.processing.applyWindow(nmrData, 'em', 'lb', 0.3);
nmrData = nmr.processing.doFFT(nmrData);
nmrData = nmr.processing.autoPhase(nmrData);
nmrData = nmr.processing.correctBaseline(nmrData);
nmrData = nmr.processing.pickPeaks(nmrData);

% 4. Plot
nmr.visualization.plotSpectrum1D(nmrData);

First-time users can try scripts/quick_look.m for a one-click demo.
See docs/quickstart.md for the full guide.

Note: The Quick Start above is for standard 1H (zg/zg30).
Water-suppressed experiments and qNMR require additional settings. → See Automation Levels.


GUI (App Designer)

For interactive processing without writing code, an App Designer GUI is available.

Option How to launch
NmrAnalyzerApp (.mlapp) Open src/+nmr/+app/NmrAnalyzerApp.mlapp in the MATLAB file browser and click Run
nmrAppProto (uifigure prototype) addpath(genpath("src")); nmrAppProto

Tabs: Load → FID → Spectrum/Phase → Baseline → Peaks/Export

NMR Analyzer App

Design spec → docs/app_designer_spec.md


Use Cases

Batch conversion of a legacy Varian archive

addpath(genpath("src"));

fidDirs = dir("D:/archive/**/*.fid");           % find all .fid directories
for k = 1:numel(fidDirs)
    fidPath = fullfile(fidDirs(k).folder, fidDirs(k).name);
    nmrData = nmr.io.loadVarian(fidPath);
    nmrData = nmr.processing.applyWindow(nmrData, 'em', 'lb', 0.5);
    nmrData = nmr.processing.doFFT(nmrData);
    nmrData = nmr.processing.autoPhase(nmrData);
    nmr.io.exportJson(nmrData, sprintf("result/batch/sample_%03d.json", k));
end

Metabolomics ML preprocessing (multi-vendor)

addpath(genpath("src"));

% Load and process Bruker dataset (swap loadBruker for loadVarian / loadJeol as needed)
dirs = ["data/sample_A/1", "data/sample_B/1", "data/sample_C/1"];
dataArr = arrayfun(@nmr.io.loadBruker, dirs, 'UniformOutput', false);
dataArr = cellfun(@(d) nmr.processing.applyWindow(d, 'em'), dataArr, 'UniformOutput', false);
dataArr = cellfun(@nmr.processing.doFFT,           dataArr, 'UniformOutput', false);
dataArr = cellfun(@nmr.processing.autoPhase,       dataArr, 'UniformOutput', false);
dataArr = cellfun(@nmr.processing.correctBaseline, dataArr, 'UniformOutput', false);

T      = nmr.ml.buildFeatureMatrix([dataArr{:}]);   % uniform binning + PQN normalisation
result = nmr.ml.runPCA(T);                           % scores, loadings, explained variance

Automation Levels

NMR samples and experiment conditions vary widely; not all data can be processed with default settings. This tool defines three levels of automation so you know upfront what is needed:

Level Meaning Example experiments
🟢 Auto Works with defaults — no configuration needed Standard ¹H (zg/zg30), ¹³C (s2pul), ¹⁹F, ¹⁵N
🟡 Preset Requires experiment-type configuration — one applyPreset call (v0.14+) Water-suppressed (presat / metnoesy / zgpr)
🔵 Manual Requires data-specific parameters (integration regions, reference, etc.) qNMR quantification, compound assignment

Preset catalog by experiment type → docs/preset_catalog.md

🟡 Preset Example — Water-Suppressed

% Water-suppressed (noesypr1d / metnoesy / presat / zgpr) — one line with applyPreset
nmrData = nmr.io.loadBruker("path/to/bruker/1");
nmrData = nmr.processing.applyPreset(nmrData, 'water_suppressed_1H');
nmr.visualization.plotSpectrum1D(nmrData, 'YLimFraction', 0.1);

Scenario-by-scenario code examples → docs/scenario_validation.md


Philosophy

NMR measurements are long-term research assets. Spectra collected years ago on older instruments should remain useful today, but they often end up locked in vendor-specific binary formats and become harder to access over time.

This project aims to bring past measurement assets back into a usable state for modern workflows.

  • Vendor-independent — unified API across Bruker, Varian, and JEOL
  • Environment-independent — runs on MATLAB Desktop or MATLAB Online without additional setup
  • Future-proofnmrData struct is decoupled from any vendor binary format

Design Principles

  • Robustness over completeness — Stability is prioritized over feature completeness
  • Real data over synthetic assumptions — Design decisions are grounded in real datasets
  • No silent failure — Anomalies are always reported

Capability Matrix

Detailed compatibility matrix (vendor × nucleus × experiment × feature) → docs/compatibility_matrix.md

Supported Formats

Format 1D FID 1D Spectrum 2D Notes
Bruker (TopSpin fid/ser + acqus) N/A¹ TopSpin 1.x–4.x / XWIN-NMR. GRPDLY auto-correction
Varian / Agilent (.fid folder) N/A¹ VnmrJ / DD2. Multi-block averaging
JEOL Delta (.jdf binary) N/A¹ Delta 5.x
JCAMP-DX (.jdx / .dx) ⚠️ AFFN + ASDF (SQZ/DIF/DUP). Only IUPAC official spec (JDX-7) ¹H / ¹³C supported. Vendor dialects ¹⁹F / ³¹P / ¹⁵N are frozen
nmrML (.nmrML XML) ⚠️ ⚠️ Complex128/64. nmrCV mapping. Only nmrML spec-conformant test data verified; real instrument output not verified

¹ Vendor binaries contain only FID (raw data). FFT and beyond are re-run through this tool by design.

Supported Nuclei × Vendor

Nucleus Bruker Varian JEOL JCAMP-DX
¹H ⚠️
¹³C ⚠️
¹⁹F
³¹P
¹⁵N 🚧
¹¹B / ²H / ²⁹Si / ²³Na / ¹⁷O 🚧 🚧 🚧 🚧

✅ = verified with real data / ⚠️ = spec/test data only (real instrument output unverified) / ⬜ = implemented but unverified / 🚧 = Blocked (Data) — unblockable once data is available / ❄️ = frozen (design or dependency reasons) ¹¹B / ²⁹Si: Phase 1 data acquired. Phase 2–4 validation is a future task. ⚠️ (JCAMP-DX): Only the IUPAC JDX-7 official test suite verified. Bruker / Varian / JEOL vendor-generated JCAMP-DX files not verified. ⚠️ (nmrML): Only nmrML spec-conformant test data verified. Real instrument-exported nmrML files not verified (no column in nuclei table — see Formats table).

Supported 2D Experiments × Vendor

Experiment Bruker Varian JEOL
COSY
DQF-COSY 🚧
TOCSY 🚧
NOESY 🚧
ROESY
HSQC (¹H-¹³C)
HMQC
HMBC 🚧
¹⁵N-HSQC
J-resolved
DEPT-HSQC ⚠️¹
DOSY

¹ DEPT-HSQC: read and displayed. DEPT classification done. Integrated atlas planned. ✅ = verified with real data / ⬜ = unverified (target for exploration) / 🚧 = Blocked (Data) (no verified raw FID in public DBs — data donations welcome → CONTRIBUTING.md) F1 detection mode: QF / TPPI / States / States-TPPI / Echo-AntiEcho all supported.

Processing Features and Automation Levels

Feature 1D 2D Automation Notes
FFT 🟢 Auto
Window function 🟡 Preset lb depends on nucleus (¹H: 0.3, ¹³C: 2.0, ¹⁹F: 1.0 Hz)
Zero-fill 🟢 Auto factor=2 default
Auto phase correction 🟢/🟡 Standard: Auto. Water-suppressed: Preset (method='abs')
Manual phase correction 🔵 Manual Explicit ph0/ph1
Baseline correction 🟡 Preset Method selection recommended (¹H → als, ¹³C → snip)
Peak detection ✅² 🟢/🟡 Standard: Auto. Water-suppressed: excludeRegions required
Peak fitting 🟡 Preset Lorentzian/Voigt selection
ppm calibration 🔵 Manual Reference compound required
SNR estimation 🟢 Auto Manual noise region improves accuracy
Integration 🔵 Manual ppm region specification required

² 2D cross-peak detection (detectCorrelations) implemented. 🟢 = works by default / 🟡 = experiment-type config needed / 🔵 = data-specific params needed

Analysis, Quantification, and ML

Feature Status Feature Status
qNMR internal standard PCA
GUM uncertainty PLS-DA
ICH Q2 validation T1/T2 relaxation fitting
2D cross-peak detection Feature extraction (binning/interp)
DEPT multiplicity classification Manual assignment management
DOSY diffusion coefficient fit DOSY 2D map visualization

ML features (PCA/PLS-DA/binning) support 1D spectra only.

Export

JSON · PNG (300–600 DPI) · PDF (vector) · CSV · MAT — all ✅


Key Features

  • Vendor Agnostic: JEOL / Bruker / Varian processed through a unified nmrData struct
  • Legacy Support: Recovers data from discontinued Varian/Agilent instruments
  • Fault Tolerance: Zero silent failures for missing params, truncated FID, endian mismatch, etc.
  • Large-Scale Validation: 365+ real datasets (TopSpin 1.x–4.x, XWIN-NMR, Delta 5.x, VnmrJ, DD2)
  • Open Format Hub: JCAMP-DX / nmrML → nmrData → JSON. Vendor binaries and open formats unified

Known Limitations and Roadmap

The following features are acknowledged but not currently being implemented. Contributions (data donation / Pull Requests) may unblock some of them.

Feature Status Reason
DOSY analysis Stejskal-Tanner single-exponential fit. Multi-component (CONTIN) planned
2D JCAMP-DX (NTUPLES) IUPAC test suite 8/8 PASS
JEOL Arrayed FID (J-03) T1/T2 arrayed FID (legacy Delta format) supported
¹¹B real-data validation 🚧 Blocked (Data) No raw FID in public DBs (Phase I–VI survey done). Data donations welcome
²H / ²⁹Si / ²³Na validation 🚧 Blocked (Data) No raw FID in public DBs. Instrument data required
Varian DQF-COSY / HMBC validation 🚧 Blocked (Data) All public DBs searched (Zenodo / Figshare / Workbench / OSF / HMDB). No raw FID found. Data donations welcome
JEOL TOCSY / NOESY validation 🚧 Blocked (Data) All public DBs searched (4985 chemserv entries, MRRC, Zenodo). No raw FID found. Data donations welcome
Bruker/JEOL JCAMP-DX dialects 🚧 Blocked (Data) Vendor-specific sample data unavailable. Data donations welcome
2D nmrML / NP-MRD 🚧 Blocked (Data) NP-MRD API not public. No raw 2D data available
RDKit structure integration ❄️ Frozen Python dependency + large implementation cost. Collaborators needed
Deep Learning ❄️ Frozen Training data collection is the barrier

🚧 = Blocked (Data) — unblockable once data is available. See CONTRIBUTING.md Wanted Data section. ❄️ = Frozen (design, dependencies, or other reasons beyond data). ⬜ = in progress or planned.


Tech Stack

  • MATLAB R2025b, Signal Processing Toolbox, Curve Fitting Toolbox
  • Python 3.11 (specific tasks only, isolated in venv/)

Directory Structure

ProjectRoot/
├─ main_nmr.m              # Single entry point (section-by-section execution)
├─ scripts/
│   └─ quick_look.m        # Quick demo for first-time users
├─ src/
│   ├─ +nmr/               # NMR-specific logic (MATLAB packages)
│   │   ├─ +io/            # Vendor parsers (nmr.io.loadVarian etc.)
│   │   ├─ +processing/    # FFT, windowing, phase, baseline
│   │   ├─ +visualization/ # Plot functions
│   │   ├─ +app/           # App Designer GUI (NmrAnalyzerApp.mlapp)
│   │   ├─ +pipeline/      # Orchestration, artifact creation
│   │   └─ +util/          # Log helper (nmr.util.log)
│   ├─ config/             # Config loader
│   └─ util/               # Common utilities
├─ tests/
│   ├─ unit/               # matlab.unittest-based unit tests (1,485 tests)
│   ├─ smoke/              # Real-data smoke tests
│   └─ regression/         # Regression tests
├─ data/                   # External NMR data (not tracked by Git)
├─ result/                 # Run artifacts (not tracked by Git)
├─ config/
│   └─ settings.example.json
└─ docs/                   # Design specs, release notes

Key Conventions

  • Logic only under src/. NMR-specific logic in src/+nmr/ packages
  • All parser outputs normalized to the common nmrData struct
  • Artifacts saved to result/runs/<YYYYMMDD_HHMMSS>/ (not Git-tracked)
  • Logging via nmr.util.log.info / .warn / .err / .progress (fprintf not used)

Documents

File Contents
docs/algorithm_guide.md Algorithm rationale and test validation strategy for all functions
docs/function_reference.md Full signatures and option lists for all functions
docs/function_catalog.md Compact function catalog (60 functions, all packages)
docs/test_catalog.md Test class catalog (50 classes, 1,485 tests)
docs/quickstart.md Step-by-step guide and FAQ
docs/compatibility_matrix.md Vendor × nucleus × experiment × feature detailed matrix

License

MIT License. See LICENSE for details.

This project implements algorithms described in published academic papers. See THIRD_PARTY_NOTICES.md for algorithm attributions.


Data Policy

This repository contains no NMR raw data.

  • data/external/ is distributed empty. Place your own data there.
  • Redistribution of data downloaded from MetaboLights / BMRB / HMDB etc. is not performed.
  • This tool does not transmit any data externally.

Disclaimer & Support

This project is developed and maintained as a personal side project.

  • Users are responsible for verifying the accuracy of results.
  • Support is best-effort. Response times may vary.
  • Provided "as-is" (see MIT License disclaimer).

Contributing

Issues and requests are welcome. See CONTRIBUTING.md for details.

  • Bug reports: Include steps to reproduce and your MATLAB version.
  • New vendor/experiment support: Describe the format and a public database link if available.
  • Analysis requests: Open an Issue to propose new processing/analysis methods.

Pull Requests are welcome, but please discuss via Issue first.

About

Open any NMR data. Read Bruker / Varian / JEOL raw FIDs — universal MATLAB toolbox.

Topics

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages