This is an automated email from the git hooks/post-receive script. yoh pushed a commit to annotated tag v0.1 in repository python-mne.
commit 69291b016bc4f4a6360f3d6e409e978493487d72 Author: Alexandre Gramfort <[email protected]> Date: Thu Dec 30 14:00:21 2010 -0500 now writing evoked data --- examples/read_evoked.py | 6 ++ fiff/__init__.py | 2 +- fiff/ctf.py | 102 +++++++++++++++------ fiff/evoked.py | 176 +++++++++++++++++++++++++++++++----- fiff/open.py | 7 -- fiff/tag.py | 1 - fiff/tests/test_evoked.py | 32 +++++++ fiff/tree.py | 75 +++++++++++++--- fiff/write.py | 222 +++++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 545 insertions(+), 78 deletions(-) diff --git a/examples/read_evoked.py b/examples/read_evoked.py index 8fe664f..08a3946 100644 --- a/examples/read_evoked.py +++ b/examples/read_evoked.py @@ -8,6 +8,12 @@ fname = 'MNE-sample-data/MEG/sample/sample_audvis-ave.fif' data = fiff.read_evoked(fname) +fiff.write_evoked('evoked.fif', data) +data2 = fiff.read_evoked('evoked.fif') + +from scipy import linalg +print linalg.norm(data['evoked']['epochs'] - data2['evoked']['epochs']) + ############################################################################### # Show result diff --git a/fiff/__init__.py b/fiff/__init__.py index 75a998c..10be9cc 100644 --- a/fiff/__init__.py +++ b/fiff/__init__.py @@ -2,7 +2,7 @@ __version__ = '0.1.git' from .constants import FIFF from .open import fiff_open -from .evoked import read_evoked +from .evoked import read_evoked, write_evoked from .cov import read_cov, write_cov, write_cov_file from .raw import setup_read_raw, read_raw_segment, read_raw_segment_times from .event import read_events diff --git a/fiff/ctf.py b/fiff/ctf.py index 2bfb52f..f5c7461 100644 --- a/fiff/ctf.py +++ b/fiff/ctf.py @@ -23,42 +23,45 @@ def read_named_matrix(fid, node, matkind): for k in range(node.nchild): if node.children(k).block == FIFF.FIFFB_MNE_NAMED_MATRIX: if has_tag(node.children(k), matkind): - node = node.children(k); - break; + node = node.children(k) + break else: - raise ValueError, 'Desired named matrix (kind = %d) not available' % matkind + raise ValueError, 'Desired named matrix (kind = %d) not' \ + ' available' % matkind else: - if not has_tag(node,matkind): - raise 'Desired named matrix (kind = %d) not available' % matkind + if not has_tag(node, matkind): + raise 'Desired named matrix (kind = %d) not available' % matkind # Read everything we need tag = find_tag(fid, node, matkind) if tag is None: - raise ValueError, 'Matrix data missing' + raise ValueError, 'Matrix data missing' else: - data = tag.data; + data = tag.data nrow, ncol = data.shape tag = find_tag(fid, node, FIFF.FIFF_MNE_NROW) if tag is not None: - if tag.data != nrow: - raise ValueError, 'Number of rows in matrix data and FIFF_MNE_NROW tag do not match' + if tag.data != nrow: + raise ValueError, 'Number of rows in matrix data and ' \ + 'FIFF_MNE_NROW tag do not match' tag = find_tag(fid, node, FIFF.FIFF_MNE_NCOL) if tag is not None: - if tag.data != ncol: - raise ValueError, 'Number of columns in matrix data and FIFF_MNE_NCOL tag do not match' + if tag.data != ncol: + raise ValueError, 'Number of columns in matrix data and ' \ + 'FIFF_MNE_NCOL tag do not match' tag = find_tag(fid, node, FIFF.FIFF_MNE_ROW_NAMES) if tag is not None: - row_names = tag.data; + row_names = tag.data else: row_names = None tag = find_tag(fid, node, FIFF.FIFF_MNE_COL_NAMES) if tag is not None: - col_names = tag.data; + col_names = tag.data else: col_names = None @@ -74,7 +77,7 @@ def read_named_matrix(fid, node, matkind): else: mat['col_names'] = None - mat['data'] = data; + mat['data'] = data return mat @@ -93,12 +96,12 @@ def read_ctf_comp(fid, node, chs): for node in comps: # Read the data we need - mat = read_named_matrix(fid, node, FIFF.FIFF_MNE_CTF_COMP_DATA) + mat = read_named_matrix(fid, node, FIFF.FIFF_MNE_CTF_COMP_DATA) for p in range(node.nent): kind = node.dir[p].kind - pos = node.dir[p].pos + pos = node.dir[p].pos if kind == FIFF.FIFF_MNE_CTF_COMP_KIND: - tag = read_tag(fid,pos) + tag = read_tag(fid, pos) break else: raise ValueError, 'Compensation type not found' @@ -118,15 +121,15 @@ def read_ctf_comp(fid, node, chs): for p in range(node.nent): kind = node.dir[p].kind - pos = node.dir[p].pos + pos = node.dir[p].pos if kind == FIFF.FIFF_MNE_CTF_COMP_CALIBRATED: - tag = read_tag(fid,pos) + tag = read_tag(fid, pos) calibrated = tag.data break else: calibrated = False - one['save_calibrated'] = calibrated; + one['save_calibrated'] = calibrated one['rowcals'] = np.ones(1, mat.shape[0]) one['colcals'] = np.ones(1, mat.shape[1]) if not calibrated: @@ -143,9 +146,11 @@ def read_ctf_comp(fid, node, chs): for col in range(mat.data.shape[1]): p = ch_names.count(mat.col_names[col]) if p == 0: - raise ValueError, 'Channel %s is not available in data' % mat.col_names[col] + raise ValueError, 'Channel %s is not available in data' \ + % mat.col_names[col] elif p > 1: - raise ValueError, 'Ambiguous channel %s' % mat.col_names[col] + raise ValueError, 'Ambiguous channel %s' % \ + mat.col_names[col] col_cals[col] = 1.0 / (chs[p].range * chs[p].cal) @@ -154,13 +159,16 @@ def read_ctf_comp(fid, node, chs): for row in range(mat.data.shape[0]): p = ch_names.count(mat.row_names[row]) if p == 0: - raise ValueError, 'Channel %s is not available in data', mat.row_names[row] + raise ValueError, 'Channel %s is not available in data' \ + % mat.row_names[row] elif p > 1: - raise ValueError, 'Ambiguous channel %s' % mat.row_names[row] + raise ValueError, 'Ambiguous channel %s' % \ + mat.row_names[row] row_cals[row] = chs[p].range * chs[p].cal - mat.data = np.dot(np.diag(row_cals), np.dot(mat.data, np.diag(col_cals))) + mat.data = np.dot(np.diag(row_cals), np.dot(mat.data, + np.diag(col_cals))) one.rowcals = row_cals one.colcals = col_cals @@ -173,3 +181,47 @@ def read_ctf_comp(fid, node, chs): print '\tRead %d compensation matrices\n' % len(compdata) return compdata + + +############################################################################### +# Writing + +from scipy import linalg +from .write import start_block, end_block, write_int, write_named_matrix + + +def write_ctf_comp(fid, comps): + """ + % + % fiff_write_ctf_comp(fid,comps) + % + % Writes the CTF compensation data into a fif file + % + % fid An open fif file descriptor + % comps The compensation data to write + % + """ + + if len(comps) <= 0: + return + + # This is very simple in fact + start_block(fid, FIFF.FIFFB_MNE_CTF_COMP) + for comp in comps: + start_block(fid, FIFF.FIFFB_MNE_CTF_COMP_DATA) + # Write the compensation kind + write_int(fid, FIFF.FIFF_MNE_CTF_COMP_KIND, comp['ctfkind']) + write_int(fid, FIFF.FIFF_MNE_CTF_COMP_CALIBRATED, + comp['save_calibrated']) + + # Write an uncalibrated or calibrated matrix + import pdb; pdb.set_trace() + + comp['data']['data'] = linalg.inv( + np.dot(np.diag(comp['rowcals'].ravel())), + np.dot(comp.data.data, + linalg.inv(np.diag(comp.colcals.ravel())))) + write_named_matrix(fid, FIFF.FIFF_MNE_CTF_COMP_DATA, comp['data']) + end_block(fid, FIFF.FIFFB_MNE_CTF_COMP_DATA) + + end_block(fid, FIFF.FIFFB_MNE_CTF_COMP) diff --git a/fiff/evoked.py b/fiff/evoked.py index 09cd9f3..013c481 100644 --- a/fiff/evoked.py +++ b/fiff/evoked.py @@ -16,22 +16,22 @@ def read_evoked(fname, setno=0): """ if setno < 0: - raise ValueError, 'Data set selector must be positive' + raise ValueError, 'Data set selector must be positive' print 'Reading %s ...\n' % fname - fid, tree, _ = fiff_open(fname); + fid, tree, _ = fiff_open(fname) # Read the measurement info info, meas = read_meas_info(fid, tree) info['filename'] = fname # Locate the data of interest - processed = dir_tree_find(meas,FIFF.FIFFB_PROCESSED_DATA); + processed = dir_tree_find(meas, FIFF.FIFFB_PROCESSED_DATA) if len(processed) == 0: fid.close() raise ValueError, 'Could not find processed data' - evoked = dir_tree_find(meas,FIFF.FIFFB_EVOKED) + evoked = dir_tree_find(meas, FIFF.FIFFB_EVOKED) if len(evoked) == 0: fid.close(fid) raise ValueError, 'Could not find evoked data' @@ -54,13 +54,13 @@ def read_evoked(fname, setno=0): is_smsh = np.c_[is_smsh, np.zeros((1, sets[k]['naspect']))] naspect += sets[k]['naspect'] - saspects = dir_tree_find(evoked[k], FIFF.FIFFB_SMSH_ASPECT) + saspects = dir_tree_find(evoked[k], FIFF.FIFFB_SMSH_ASPECT) nsaspects = len(saspects) if nsaspects > 0: sets[k]['naspect'] += nsaspects sets[k]['naspect'] = [sets[k]['naspect'], saspects] # XXX : potential bug is_smsh = np.c_[is_smsh, np.ones(1, sets[k]['naspect'])] - naspect += nsaspects; + naspect += nsaspects print '\t%d evoked data sets containing a total of %d data aspects' \ ' in %s\n' % (len(evoked), naspect, fname) @@ -96,7 +96,7 @@ def read_evoked(fname, setno=0): comment = None for k in range(my_evoked.nent): kind = my_evoked.directory[k].kind - pos = my_evoked.directory[k].pos + pos = my_evoked.directory[k].pos if kind == FIFF.FIFF_COMMENT: tag = read_tag(fid, pos) comment = tag.data @@ -118,37 +118,39 @@ def read_evoked(fname, setno=0): q += 1 if comment is None: - comment = 'No comment' + comment = 'No comment' # Local channel information? if nchan > 0: if chs is None: fid.close() - raise ValueError, 'Local channel information was not found when it was expected.' + raise ValueError, 'Local channel information was not found ' \ + 'when it was expected.' if len(chs) != nchan: fid.close() - raise ValueError, 'Number of channels and number of channel definitions are different' + raise ValueError, 'Number of channels and number of channel ' \ + 'definitions are different' info.chs = chs info.nchan = nchan - print '\tFound channel information in evoked data. nchan = %d\n' % nchan + print '\tFound channel information in evoked data. nchan = %d' % nchan if sfreq > 0: info['sfreq'] = sfreq nsamp = last - first + 1 - print '\tFound the data of interest:\n' - print '\t\tt = %10.2f ... %10.2f ms (%s)\n' % ( + print '\tFound the data of interest:' + print '\t\tt = %10.2f ... %10.2f ms (%s)' % ( 1000*first/info['sfreq'], 1000*last/info['sfreq'], comment) if info['comps'] is not None: - print '\t\t%d CTF compensation matrices available\n' % len(info['comps']) + print '\t\t%d CTF compensation matrices available' % len(info['comps']) # Read the data in the aspect block nave = 1 epoch = [] for k in range(my_aspect.nent): kind = my_aspect.directory[k].kind - pos = my_aspect.directory[k].pos + pos = my_aspect.directory[k].pos if kind == FIFF.FIFF_COMMENT: tag = read_tag(fid, pos) comment = tag.data @@ -171,11 +173,11 @@ def read_evoked(fname, setno=0): '(nepoch = %d nchan = %d)' % (nepoch, info.nchan) if nepoch == 1: - # Only one epoch - all_data = epoch[0].data - # May need a transpose if the number of channels is one - if all_data.shape[1] == 1 and info.nchan == 1: - all_data = all_data.T + # Only one epoch + all_data = epoch[0].data + # May need a transpose if the number of channels is one + if all_data.shape[1] == 1 and info.nchan == 1: + all_data = all_data.T else: # Put the old style epochs together @@ -204,3 +206,137 @@ def read_evoked(fname, setno=0): fid.close() return data + +############################################################################### +# Writing + +from .tree import copy_tree +from .write import start_file, start_block, end_file, end_block, write_id, \ + write_float, write_int, write_coord_trans, write_ch_info, \ + write_dig_point, write_name_list, write_string, \ + write_float_matrix +from .proj import write_proj +from .ctf import write_ctf_comp + + +def write_evoked(name, data): + """ + % + % function fiff_write_evoked(name,data) + % + % name filename + % data the data structure returned from fiff_read_evoked + % + % + """ + + # Create the file and save the essentials + fid = start_file(name) + start_block(fid, FIFF.FIFFB_MEAS) + write_id(fid, FIFF.FIFF_BLOCK_ID) + if data['info']['meas_id'] is not None: + write_id(fid, FIFF.FIFF_PARENT_BLOCK_ID, data['info']['meas_id']) + + # Measurement info + start_block(fid, FIFF.FIFFB_MEAS_INFO) + + # Blocks from the original + blocks = [FIFF.FIFFB_SUBJECT, FIFF.FIFFB_HPI_MEAS, FIFF.FIFFB_HPI_RESULT, + FIFF.FIFFB_ISOTRAK, FIFF.FIFFB_PROCESSING_HISTORY] + + have_hpi_result = False + have_isotrak = False + if len(blocks) > 0 and 'filename' in data['info'] and \ + data['info']['filename'] is not None: + fid2, tree, _ = fiff_open(data['info']['filename']) + for block in blocks: + nodes = dir_tree_find(tree, block) + copy_tree(fid2, tree['id'], nodes, fid) + if block == FIFF.FIFFB_HPI_RESULT and len(nodes) > 0: + have_hpi_result = True + if block == FIFF.FIFFB_ISOTRAK and len(nodes) > 0: + have_isotrak = True + fid2.close() + + + # General + write_float(fid, FIFF.FIFF_SFREQ, data['info']['sfreq']) + write_float(fid, FIFF.FIFF_HIGHPASS, data['info']['highpass']) + write_float(fid, FIFF.FIFF_LOWPASS, data['info']['lowpass']) + write_int(fid, FIFF.FIFF_NCHAN, data['info']['nchan']) + if data['info']['meas_date'] is not None: + write_int(fid, FIFF.FIFF_MEAS_DATE, data['info']['meas_date']) + + # Coordinate transformations if the HPI result block was not there + if not have_hpi_result: + if data['info']['dev_head_t'] is not None: + write_coord_trans(fid, data['info']['dev_head_t']) + + if data['info']['ctf_head_t'] is not None: + write_coord_trans(fid, data['info']['ctf_head_t']) + + # Channel information + for k in range(data['info']['nchan']): + # Scan numbers may have been messed up + data['info']['chs'][k]['scanno'] = k + write_ch_info(fid, data['info']['chs'][k]) + + # Polhemus data + if data['info']['dig'] is not None and not have_isotrak: + start_block(fid, FIFF.FIFFB_ISOTRAK) + for d in data['info']['dig']: + write_dig_point(fid, d) + + end_block(fid, FIFF.FIFFB_ISOTRAK) + + # Projectors + write_proj(fid, data['info']['projs']) + + # CTF compensation info + write_ctf_comp(fid, data['info']['comps']) + + # Bad channels + if len(data['info']['bads']) > 0: + start_block(fid, FIFF.FIFFB_MNE_BAD_CHANNELS) + write_name_list(fid, FIFF.FIFF_MNE_CH_NAME_LIST, data['info']['bads']) + end_block(fid, FIFF.FIFFB_MNE_BAD_CHANNELS) + + end_block(fid, FIFF.FIFFB_MEAS_INFO) + + # One or more evoked data sets + start_block(fid, FIFF.FIFFB_PROCESSED_DATA) + data_evoked = data['evoked'] + if not isinstance(data_evoked, list): + data_evoked = [data_evoked] + + for evoked in data_evoked: + start_block(fid, FIFF.FIFFB_EVOKED) + + # Comment is optional + if len(evoked['comment']) > 0: + write_string(fid, FIFF.FIFF_COMMENT, evoked['comment']) + + # First and last sample + write_int(fid, FIFF.FIFF_FIRST_SAMPLE, evoked['first']) + write_int(fid, FIFF.FIFF_LAST_SAMPLE, evoked['last']) + + # The epoch itself + start_block(fid, FIFF.FIFFB_ASPECT) + + write_int(fid, FIFF.FIFF_ASPECT_KIND, evoked['aspect_kind']) + write_int(fid, FIFF.FIFF_NAVE, evoked['nave']) + + decal = np.zeros((data['info']['nchan'], data['info']['nchan'])) + for k in range(data['info']['nchan']): # XXX : can be improved + decal[k, k] = 1.0 / data['info']['chs'][k]['cal'] + + write_float_matrix(fid, FIFF.FIFF_EPOCH, + np.dot(decal, evoked['epochs'])) + end_block(fid, FIFF.FIFFB_ASPECT) + end_block(fid, FIFF.FIFFB_EVOKED) + + end_block(fid, FIFF.FIFFB_PROCESSED_DATA) + + end_block(fid, FIFF.FIFFB_MEAS) + + end_file(fid) diff --git a/fiff/open.py b/fiff/open.py index 25ca967..5feaa90 100644 --- a/fiff/open.py +++ b/fiff/open.py @@ -9,9 +9,7 @@ def fiff_open(fname, verbose=False): tag = read_tag_info(fid) - # # Check that this looks like a fif file - # if tag.kind != FIFF.FIFF_FILE_ID: raise ValueError, 'file does not start with a file id tag' @@ -26,9 +24,7 @@ def fiff_open(fname, verbose=False): if tag.kind != FIFF.FIFF_DIR_POINTER: raise ValueError, 'file does have a directory pointer' - # # Read or create the directory tree - # if verbose: print '\tCreating tag directory for %s...' % fname @@ -50,10 +46,7 @@ def fiff_open(fname, verbose=False): if verbose: print '[done]\n' - # # Back to the beginning - # fid.seek(0) - # fid.close() return fid, tree, directory diff --git a/fiff/tag.py b/fiff/tag.py index 9655cf3..d932272 100644 --- a/fiff/tag.py +++ b/fiff/tag.py @@ -129,7 +129,6 @@ def read_tag(fid, pos=None): # All other data types # Simple types - if tag.type == FIFF.FIFFT_BYTE: tag.data = np.fromfile(fid, dtype=">B1", count=tag.size) elif tag.type == FIFF.FIFFT_SHORT: diff --git a/fiff/tests/test_evoked.py b/fiff/tests/test_evoked.py new file mode 100644 index 0000000..52e7178 --- /dev/null +++ b/fiff/tests/test_evoked.py @@ -0,0 +1,32 @@ +import os +import os.path as op + +import numpy as np +from numpy.testing import assert_array_almost_equal, assert_equal + +import fiff + +MNE_SAMPLE_DATASET_PATH = os.getenv('MNE_SAMPLE_DATASET_PATH') +fname = op.join(MNE_SAMPLE_DATASET_PATH, 'MEG', 'sample', + 'sample_audvis-ave.fif') + +def test_io_cov(): + """Test IO for noise covariance matrices + """ + data = fiff.read_evoked(fname) + + fiff.write_evoked('evoked.fif', data) + data2 = fiff.read_evoked('evoked.fif') + + print assert_array_almost_equal(data['evoked']['epochs'], + data2['evoked']['epochs']) + print assert_array_almost_equal(data['evoked']['times'], + data2['evoked']['times']) + print assert_equal(data['evoked']['nave'], + data2['evoked']['nave']) + print assert_equal(data['evoked']['aspect_kind'], + data2['evoked']['aspect_kind']) + print assert_equal(data['evoked']['last'], + data2['evoked']['last']) + print assert_equal(data['evoked']['first'], + data2['evoked']['first']) diff --git a/fiff/tree.py b/fiff/tree.py index 2ce7871..86b23c1 100644 --- a/fiff/tree.py +++ b/fiff/tree.py @@ -73,22 +73,22 @@ def make_dir_tree(fid, directory, start=0, indent=0, verbose=False): # Add the id information if available if block == 0: - if directory[this].kind == FIFF_FILE_ID: - tag = read_tag(fid, directory[this].pos) - tree.id = tag.data + if directory[this].kind == FIFF_FILE_ID: + tag = read_tag(fid, directory[this].pos) + tree.id = tag.data else: - if directory[this].kind == FIFF_BLOCK_ID: - tag = read_tag(fid, directory[this].pos) - tree.id = tag.data - elif directory[this].kind == FIFF_PARENT_BLOCK_ID: - tag = read_tag(fid, directory[this].pos) - tree.parent_id = tag.data + if directory[this].kind == FIFF_BLOCK_ID: + tag = read_tag(fid, directory[this].pos) + tree.id = tag.data + elif directory[this].kind == FIFF_PARENT_BLOCK_ID: + tag = read_tag(fid, directory[this].pos) + tree.parent_id = tag.data this += 1 # Eliminate the empty directory if tree.nent == 0: - tree.directory = None + tree.directory = None if verbose: print '\t'*(indent+1) + 'block = %d nent = %d nchild = %d' % ( @@ -97,3 +97,58 @@ def make_dir_tree(fid, directory, start=0, indent=0, verbose=False): last = this return tree, last + +############################################################################### +# Writing + +import numpy as np +import struct +from .constants import FIFF +from .tag import Tag +from .write import write_id, start_block, end_block, _write + + +def copy_tree(fidin, in_id, nodes, fidout): + """ + % + % fiff_copy_tree(fidin, in_id, nodes, fidout) + % + % Copies directory subtrees from fidin to fidout + % + """ + + if len(nodes) <= 0: + return + + if not isinstance(nodes, list): + nodes = [nodes] + + for node in nodes: + start_block(fidout, node.block) + if node['id'] is not None: + if in_id is not None: + write_id(fidout, FIFF.FIFF_PARENT_FILE_ID, in_id) + + write_id(fidout, FIFF.FIFF_BLOCK_ID) + write_id(fidout, FIFF.FIFF_PARENT_BLOCK_ID, node['id']) + + for d in node.directory: + # Do not copy these tags + if d.kind == FIFF.FIFF_BLOCK_ID or \ + d.kind == FIFF.FIFF_PARENT_BLOCK_ID or \ + d.kind == FIFF.FIFF_PARENT_FILE_ID: + continue + + # Read and write tags, pass data through transparently + fidin.seek(d.pos, 0) + + s = fidin.read(4*4) + tag = Tag(*struct.unpack(">iIii", s)) + tag.data = np.fromfile(fidin, dtype='>B', count=tag.size) + + _write(fidout, tag.data, tag.kind, 1, tag.type, '>B') + + for child in node['children']: + copy_tree(fidin, in_id, child, fidout) + + end_block(fidout, node.block) diff --git a/fiff/write.py b/fiff/write.py index e7e55c9..a0091b8 100644 --- a/fiff/write.py +++ b/fiff/write.py @@ -1,5 +1,7 @@ import time +import array import numpy as np +from scipy import linalg from .constants import FIFF @@ -8,6 +10,8 @@ def _write(fid, data, kind, data_size, FIFFT_TYPE, dtype): FIFFV_NEXT_SEQ = 0 if isinstance(data, np.ndarray): data_size *= data.size + if isinstance(data, str): + data_size *= len(data) fid.write(np.array(kind, dtype='>i4').tostring()) fid.write(np.array(FIFFT_TYPE, dtype='>i4').tostring()) fid.write(np.array(data_size, dtype='>i4').tostring()) @@ -79,7 +83,7 @@ def write_string(fid, kind, data): % """ FIFFT_STRING = 10 - data_size = len(data) + data_size = 1 _write(fid, data, kind, data_size, FIFFT_STRING, '>c') @@ -98,33 +102,39 @@ def write_name_list(fid, kind, data): write_string(fid, kind, ':'.join(data)) -def write_float_matrix(fid, kind, data): +def write_float_matrix(fid, kind, mat): """ % % fiff_write_float_matrix(fid,kind,mat) - % + % % Writes a single-precision floating-point matrix tag % % fid An open fif file descriptor % kind The tag kind - % data The data matrix + % mat The data matrix % """ - FIFFT_FLOAT = 4 FIFFT_MATRIX = 1 << 30 FIFFT_MATRIX_FLOAT = FIFFT_FLOAT | FIFFT_MATRIX - data_size = 4*data.size + 4*3 + FIFFV_NEXT_SEQ = 0 - _write(fid, data, kind, data_size, FIFFT_MATRIX_FLOAT, '>f4') + data_size = 4 * mat.size + 4 * 3 - dims = np.empty(3, dtype=np.int) - dims[0] = data.shape[1] - dims[1] = data.shape[0] - dims[3] = 2 + fid.write(np.array(kind, dtype='>i4').tostring()) + fid.write(np.array(FIFFT_MATRIX_FLOAT, dtype='>i4').tostring()) + fid.write(np.array(data_size, dtype='>i4').tostring()) + fid.write(np.array(FIFFV_NEXT_SEQ, dtype='>i4').tostring()) + fid.write(np.array(mat, dtype='>f4').tostring()) + + dims = np.empty(3, dtype=np.int32) + dims[0] = mat.shape[1] + dims[1] = mat.shape[0] + dims[2] = 2 fid.write(np.array(dims, dtype='>i4').tostring()) + def write_id(fid, kind, id_=None): """ % @@ -142,7 +152,7 @@ def write_id(fid, kind, id_=None): if id_ is None: id_ = dict() - id_['version'] = (1 << 16) | 2 # Version (1 << 16) | 2 + id_['version'] = (1 << 16) | 2 id_['machid'] = 65536 * np.random.rand(2) # Machine id (andom for now) id_['secs'] = time.time() id_['usecs'] = 0 # Do not know how we could get this XXX @@ -233,11 +243,195 @@ def end_file(fid): % fid An open fif file descriptor % """ - data_size = 0 - fid.write(np.array(FIFF.FIFF_NOP, dtype='>i4').tostring()) fid.write(np.array(FIFF.FIFFT_VOID, dtype='>i4').tostring()) fid.write(np.array(data_size, dtype='>i4').tostring()) fid.write(np.array(FIFF.FIFFV_NEXT_NONE, dtype='>i4').tostring()) fid.close() + + +def write_coord_trans(fid, trans): + """ + # + # fiff_write_coord_trans(fid,trans) + # + # Writes a coordinate transformation structure + # + # fid An open fif file descriptor + # trans The coordinate transfomation structure + # + """ + + FIFF_COORD_TRANS = 222 + FIFFT_COORD_TRANS_STRUCT = 35 + FIFFV_NEXT_SEQ = 0 + + #?typedef struct _fiffCoordTransRec { + # fiff_int_t from; /*!< Source coordinate system. */ + # fiff_int_t to; /*!< Destination coordinate system. */ + # fiff_float_t rot[3][3]; /*!< The forward transform (rotation part) */ + # fiff_float_t move[3]; /*!< The forward transform (translation part) */ + # fiff_float_t invrot[3][3]; /*!< The inverse transform (rotation part) */ + # fiff_float_t invmove[3]; /*!< The inverse transform (translation part) */ + #} *fiffCoordTrans, fiffCoordTransRec; /*!< Coordinate transformation descriptor */ + + data_size = 4*2*12 + 4*2 + fid.write(np.array(FIFF_COORD_TRANS, dtype='>i4').tostring()) + fid.write(np.array(FIFFT_COORD_TRANS_STRUCT, dtype='>i4').tostring()) + fid.write(np.array(data_size, dtype='>i4').tostring()) + fid.write(np.array(FIFFV_NEXT_SEQ, dtype='>i4').tostring()) + fid.write(np.array(trans['from_'], dtype='>i4').tostring()) + fid.write(np.array(trans['to'], dtype='>i4').tostring()) + + # The transform... + rot = trans['trans'][:3, :3] + move = trans['trans'][:3, 3] + fid.write(np.array(rot, dtype='>f4').tostring()) + fid.write(np.array(move, dtype='>f4').tostring()) + + # ...and its inverse + trans_inv = linalg.inv(trans.trans) + rot = trans_inv[:3, :3] + move = trans_inv[:3, 3] + fid.write(np.array(rot, dtype='>f4').tostring()) + fid.write(np.array(move, dtype='>f4').tostring()) + + +def write_ch_info(fid, ch): + """ + % + % fiff_write_ch_info(fid,ch) + % + % Writes a channel information record to a fif file + % + % fid An open fif file descriptor + % ch The channel information structure to write + % + % The type, cal, unit, and pos members are explained in Table 9.5 + % of the MNE manual + % + """ + + FIFF_CH_INFO = 203 + FIFFT_CH_INFO_STRUCT = 30 + FIFFV_NEXT_SEQ = 0 + + #typedef struct _fiffChPosRec { + # fiff_int_t coil_type; /*!< What kind of coil. */ + # fiff_float_t r0[3]; /*!< Coil coordinate system origin */ + # fiff_float_t ex[3]; /*!< Coil coordinate system x-axis unit vector */ + # fiff_float_t ey[3]; /*!< Coil coordinate system y-axis unit vector */ + # fiff_float_t ez[3]; /*!< Coil coordinate system z-axis unit vector */ + #} fiffChPosRec,*fiffChPos; /*!< Measurement channel position and coil type */ + + + #typedef struct _fiffChInfoRec { + # fiff_int_t scanNo; /*!< Scanning order # */ + # fiff_int_t logNo; /*!< Logical channel # */ + # fiff_int_t kind; /*!< Kind of channel */ + # fiff_float_t range; /*!< Voltmeter range (only applies to raw data ) */ + # fiff_float_t cal; /*!< Calibration from volts to... */ + # fiff_ch_pos_t chpos; /*!< Channel location */ + # fiff_int_t unit; /*!< Unit of measurement */ + # fiff_int_t unit_mul; /*!< Unit multiplier exponent */ + # fiff_char_t ch_name[16]; /*!< Descriptive name for the channel */ + #} fiffChInfoRec,*fiffChInfo; /*!< Description of one channel */ + + data_size = 4*13 + 4*7 + 16; + + fid.write(np.array(FIFF_CH_INFO, dtype='>i4').tostring()) + fid.write(np.array(FIFFT_CH_INFO_STRUCT, dtype='>i4').tostring()) + fid.write(np.array(data_size, dtype='>i4').tostring()) + fid.write(np.array(FIFFV_NEXT_SEQ, dtype='>i4').tostring()) + + # Start writing fiffChInfoRec + fid.write(np.array(ch['scanno'], dtype='>i4').tostring()) + fid.write(np.array(ch['logno'], dtype='>i4').tostring()) + fid.write(np.array(ch['kind'], dtype='>i4').tostring()) + fid.write(np.array(ch['range'], dtype='>f4').tostring()) + fid.write(np.array(ch['cal'], dtype='>f4').tostring()) + fid.write(np.array(ch['coil_type'], dtype='>i4').tostring()) + fid.write(np.array(ch['loc'], dtype='>f4').tostring()) # writing 12 values + + # unit and unit multiplier + fid.write(np.array(ch['unit'], dtype='>i4').tostring()) + fid.write(np.array(ch['unit_mul'], dtype='>i4').tostring()) + + # Finally channel name + if len(ch['ch_name']): + ch_name = ch['ch_name'][:15] + else: + ch_name = ch['ch_name'] + + fid.write(np.array(ch_name, dtype='>c').tostring()) + if len(ch_name) < 16: + dum = array.array('c', '\0' * (16 - len(ch_name))) + dum.tofile(fid) + + +def write_dig_point(fid, dig): + """ + % + % fiff_write_dig_point(fid,dig) + % + % Writes a digitizer data point into a fif file + % + % fid An open fif file descriptor + % dig The point to write + % + """ + + FIFF_DIG_POINT = 213 + FIFFT_DIG_POINT_STRUCT = 33 + FIFFV_NEXT_SEQ = 0 + + #?typedef struct _fiffDigPointRec { + # fiff_int_t kind; /*!< FIFF_POINT_CARDINAL, + # * FIFF_POINT_HPI, or + # * FIFF_POINT_EEG */ + # fiff_int_t ident; /*!< Number identifying this point */ + # fiff_float_t r[3]; /*!< Point location */ + #} *fiffDigPoint,fiffDigPointRec; /*!< Digitization point description */ + + data_size = 5 * 4 + + fid.write(np.array(FIFF_DIG_POINT, dtype='>i4').tostring()) + fid.write(np.array(FIFFT_DIG_POINT_STRUCT, dtype='>i4').tostring()) + fid.write(np.array(data_size, dtype='>i4').tostring()) + fid.write(np.array(FIFFV_NEXT_SEQ, dtype='>i4').tostring()) + + # Start writing fiffDigPointRec + fid.write(np.array(dig['kind'], dtype='>i4').tostring()) + fid.write(np.array(dig['ident'], dtype='>i4').tostring()) + fid.write(np.array(dig['r'][:3], dtype='>f4').tostring()) + + +def write_named_matrix(fid, kind, mat): + """ + % + % fiff_write_named_matrix(fid,kind,mat) + % + % Writes a named single-precision floating-point matrix + % + % fid An open fif file descriptor + % kind The tag kind to use for the data + % mat The data matrix + % + """ + + start_block(fid, FIFF.FIFFB_MNE_NAMED_MATRIX) + write_int(fid, FIFF.FIFF_MNE_NROW, mat['nrow']) + write_int(fid, FIFF.FIFF_MNE_NCOL, mat['ncol']) + + if len(mat['row_names']) > 0: + write_name_list(fid, FIFF.FIFF_MNE_ROW_NAMES, mat['row_names']) + + if len(mat['col_names']) > 0: + write_name_list(fid, FIFF.FIFF_MNE_COL_NAMES, mat['col_names']) + + write_float_matrix(fid,kind, mat.data) + end_block(fid, FIFF.FIFFB_MNE_NAMED_MATRIX) + + return; + -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/python-mne.git _______________________________________________ debian-med-commit mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit
