mirror of
https://github.com/echemdata/galvani.git
synced 2025-12-14 09:15:34 +00:00
Added class to read in .mpr files
The class currently just reads the main data section and does not process any of the headers or log information.
This commit is contained in:
75
BioLogic.py
75
BioLogic.py
@@ -5,6 +5,7 @@ __all__ = ['MPTfileCSV', 'MPTfile']
|
||||
|
||||
import re
|
||||
import csv
|
||||
from os import SEEK_SET, SEEK_CUR
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -119,3 +120,77 @@ def MPTfileCSV(file_or_path):
|
||||
raise ValueError("Unrecognised headers for MPT file format")
|
||||
|
||||
return mpt_csv, comments
|
||||
|
||||
|
||||
VMPmodule_hdr = np.dtype([('shortname', 'S10'),
|
||||
('longname', 'S25'),
|
||||
('length', '<u8'),
|
||||
('date', 'S8')])
|
||||
VMPdata_dtype = np.dtype([('flags', 'u1'),
|
||||
("time/s", '<f8'),
|
||||
("control/V/mA", '<f4'),
|
||||
("Ewe/V", '<f4'),
|
||||
("dQ/mA.h", '<f8'),
|
||||
("P/W", '<f4')])
|
||||
|
||||
|
||||
def read_VMP_modules(fileobj, read_module_data=True):
|
||||
"""Reads in module headers in the VMPmodule_hdr format. Yields a dict with
|
||||
the headers and offset for each module.
|
||||
|
||||
N.B. the offset yielded is the offset to the start of the data i.e. after
|
||||
the end of the header. The data runs from (offset) to (offset+length)"""
|
||||
while True:
|
||||
module_magic = fileobj.read(len(b'MODULE'))
|
||||
if len(module_magic) == 0: # end of file
|
||||
raise StopIteration
|
||||
elif module_magic != b'MODULE':
|
||||
raise ValueError("Found %r, expecting start of new VMP MODULE" % module_magic)
|
||||
|
||||
hdr_bytes = fileobj.read(VMPmodule_hdr.itemsize)
|
||||
if len(hdr_bytes) < VMPmodule_hdr.itemsize:
|
||||
raise IOError("Unexpected end of file while reading module header")
|
||||
|
||||
hdr = np.fromstring(hdr_bytes, dtype=VMPmodule_hdr, count=1)
|
||||
hdr_dict = dict(((n, hdr[n][0]) for n in VMPmodule_hdr.names))
|
||||
hdr_dict['offset'] = fileobj.tell()
|
||||
if read_module_data:
|
||||
hdr_dict['data'] = fileobj.read(hdr_dict['length'])
|
||||
if len(hdr_dict['data']) != hdr_dict['length']:
|
||||
raise IOError("""Unexpected end of file while reading data
|
||||
current module: %s
|
||||
length read: %d
|
||||
length expected: %d""" % (hdr_dict['longname'],
|
||||
len(hdr_dict['data']),
|
||||
hdr_dict['length']))
|
||||
yield hdr_dict
|
||||
else:
|
||||
yield hdr_dict
|
||||
fileobj.seek(hdr_dict['offset'] + hdr_dict['length'], SEEK_SET)
|
||||
|
||||
|
||||
class MPRfile:
|
||||
"""Bio-Logic .mpr file
|
||||
|
||||
The file format is not specified anywhere and has therefore been reverse
|
||||
engineered. Not all the fields are known.
|
||||
"""
|
||||
|
||||
def __init__(self, file_or_path):
|
||||
if isinstance(file_or_path, str):
|
||||
mpr_file = open(file_or_path, 'rb')
|
||||
else:
|
||||
mpr_file = file_or_path
|
||||
|
||||
mpr_magic = b'BIO-LOGIC MODULAR FILE\x1a \x00\x00\x00\x00'
|
||||
magic = mpr_file.read(len(mpr_magic))
|
||||
if magic != mpr_magic:
|
||||
raise ValueError('Invalid magic for .mpr file: %s' % magic)
|
||||
|
||||
modules = list(read_VMP_modules(mpr_file))
|
||||
self.modules = modules
|
||||
data_module, = (m for m in modules if m['shortname'] == b'VMP data ')
|
||||
|
||||
## There is 100 bytes of data before the main array starts
|
||||
self.data = np.frombuffer(data_module['data'], dtype=VMPdata_dtype,
|
||||
offset=100)
|
||||
|
||||
@@ -1 +1 @@
|
||||
from .BioLogic import MPTfile
|
||||
from .BioLogic import MPTfile, MPRfile
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
import os.path
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_almost_equal, assert_array_equal
|
||||
from nose.tools import ok_, eq_, raises
|
||||
|
||||
from ..BioLogic import MPTfile, MPTfileCSV
|
||||
from ..import MPTfile, MPRfile
|
||||
from ..BioLogic import MPTfileCSV # not exported
|
||||
|
||||
testdata_dir = os.path.join(os.path.dirname(__file__), 'testdata')
|
||||
|
||||
@@ -35,3 +38,50 @@ def test_open_MPT_csv():
|
||||
@raises(ValueError)
|
||||
def test_open_MPT_csv_fails_for_bad_file():
|
||||
mpt1 = MPTfileCSV(os.path.join(testdata_dir, 'bio-logic1.mpr'))
|
||||
|
||||
|
||||
def test_open_MPR():
|
||||
mpr1 = MPRfile(os.path.join(testdata_dir, 'bio-logic1.mpr'))
|
||||
|
||||
|
||||
@raises(ValueError)
|
||||
def test_open_MPR_fails_for_bad_file():
|
||||
mpr1 = MPRfile(os.path.join(testdata_dir, 'arbin1.res'))
|
||||
|
||||
|
||||
def test_MPR_matches_MPT():
|
||||
mpr1 = MPRfile(os.path.join(testdata_dir, 'bio-logic1.mpr'))
|
||||
mpt1, comments = MPTfile(os.path.join(testdata_dir, 'bio-logic1.mpt'))
|
||||
|
||||
assert_array_equal(mpr1.data["flags"] & 0x03, mpt1["mode"])
|
||||
assert_array_equal(np.array(mpr1.data["flags"] & 0x04, dtype=np.bool_),
|
||||
mpt1["ox/red"])
|
||||
assert_array_equal(np.array(mpr1.data["flags"] & 0x08, dtype=np.bool_),
|
||||
mpt1["error"])
|
||||
assert_array_equal(np.array(mpr1.data["flags"] & 0x10, dtype=np.bool_),
|
||||
mpt1["control changes"])
|
||||
assert_array_equal(np.array(mpr1.data["flags"] & 0x20, dtype=np.bool_),
|
||||
mpt1["Ns changes"])
|
||||
## Nothing uses the 0x40 bit of the flags
|
||||
assert_array_equal(np.array(mpr1.data["flags"] & 0x80, dtype=np.bool_),
|
||||
mpt1["counter inc."])
|
||||
|
||||
assert_array_almost_equal(mpr1.data["time/s"],
|
||||
mpt1["time/s"],
|
||||
decimal=5) # 5 digits in CSV
|
||||
|
||||
assert_array_almost_equal(mpr1.data["control/V/mA"],
|
||||
mpt1["control/V/mA"],
|
||||
decimal=6) # 32 bit float precision
|
||||
|
||||
assert_array_almost_equal(mpr1.data["Ewe/V"],
|
||||
mpt1["Ewe/V"],
|
||||
decimal=6) # 32 bit float precision
|
||||
|
||||
assert_array_almost_equal(mpr1.data["dQ/mA.h"],
|
||||
mpt1["dQ/mA.h"],
|
||||
decimal=17) # 64 bit float precision
|
||||
|
||||
assert_array_almost_equal(mpr1.data["P/W"],
|
||||
mpt1["P/W"],
|
||||
decimal=10) # 32 bit float precision for 1.xxE-5
|
||||
|
||||
Reference in New Issue
Block a user