ASAM MDF measurement data file parser
asammdf is a Python library for parsing and manipulating ASAM MDF (Measurement Data Format) files. It supports MDF versions 3 and 4, providing robust tools for reading, writing, and modifying measurement data. The library is currently at version 8.8.1 and maintains a frequent release cadence, often pushing several bug fix releases per month.
Warnings
- breaking The API for accessing signals and channel groups has undergone significant changes in versions leading up to 7.x and beyond. Older patterns, such as direct dictionary-style access to `mdf.channels` or different `get` method signatures, may no longer work or behave as expected.
- gotcha Loading extremely large MDF files (multiple gigabytes) entirely into memory using `MDF(file_path)` can lead to `MemoryError` and slow performance. The library reads the entire file by default if not specified otherwise.
- gotcha Plotting and GUI functionalities are not included in the base `asammdf` installation. Attempting to use `mdf.plot()` or `mdf.gui()` without installing the extra dependencies will result in `ImportError` or `ModuleNotFoundError`.
- breaking As of recent versions (e.g., 8.x), `asammdf` requires Python 3.10 or newer. Users attempting to install or run `asammdf` on older Python versions (e.g., 3.9 or below) will encounter dependency resolution errors or runtime failures.
- gotcha While `asammdf` supports both MDF v3 and v4, certain features or metadata structures are exclusive to specific versions. For instance, detailed bus logging (CAN/LIN) metadata and some complex block structures are primarily a v4 feature.
Install
-
pip install asammdf -
pip install "asammdf[plot]" -
pip install "asammdf[gui]"
Imports
- MDF
from asammdf import MDF
- Signal
from asammdf import Signal
Quickstart
import numpy as np
from asammdf import MDF, Signal
import os
# Create a dummy MDF file for demonstration
file_name = "example.mdf"
# Ensure clean slate for quickstart run
if os.path.exists(file_name):
os.remove(file_name)
# 1. Create some dummy signals
time_stamps = np.arange(0, 10, 0.1)
signal1_data = np.sin(time_stamps)
signal2_data = np.cos(time_stamps)
s1 = Signal(samples=signal1_data, timestamps=time_stamps, name='Engine_Speed', unit='rpm')
s2 = Signal(samples=signal2_data, timestamps=time_stamps, name='Vehicle_Speed', unit='km/h')
# 2. Write signals to a new MDF file (using context manager)
with MDF(version='4.10') as mdf_writer:
mdf_writer.append([s1, s2], comment='Basic measurement data')
mdf_writer.save(file_name, overwrite=True)
print(f"Dummy MDF file '{file_name}' created successfully.\n")
# 3. Read the MDF file back
with MDF(file_name) as mdf_reader:
print(f"File version: {mdf_reader.version}")
print(f"Available channels: {mdf_reader.channels}")
# 4. Access a specific signal by name
engine_speed_signal = mdf_reader.get('Engine_Speed')
if engine_speed_signal:
print(f"\nSignal 'Engine_Speed' unit: {engine_speed_signal.unit}")
print(f"Signal 'Engine_Speed' samples (first 5): {engine_speed_signal.samples[:5]}")
print(f"Signal 'Engine_Speed' timestamps (first 5): {engine_speed_signal.timestamps[:5]}")
# 5. Select multiple signals
selected_signals = mdf_reader.select(channels=['Engine_Speed', 'Vehicle_Speed'])
print(f"\nSelected signals count: {len(selected_signals)}")
# Clean up the dummy file
if os.path.exists(file_name):
os.remove(file_name)
print(f"\nDummy MDF file '{file_name}' cleaned up.")