bids-standard / pybv

A lightweight I/O utility for the BrainVision data format, written in Python.

Home Page:https://pybv.readthedocs.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wrong resolution in absolute terms is printed to vhdr

sappelhoff opened this issue · comments

this is a separate issue from #48

looking at the following code, we see that the "resolution" for each channel first passes through "optimize_channel_unit"

pybv/pybv/io.py

Lines 276 to 281 in 76e8bea

for i in range(nchan):
resolution, unit = _optimize_channel_unit(resolutions[i], units[i])
s = r'Ch{}={},,{:0.{precision}f},{}'
print(s.format(i + 1, ch_names[i], resolution, unit,
precision=max(0, int(np.log10(1 / resolution)))),
file=fout)

Yet "optimize_channel_unit" changes the resolution to account for conversion of units:

pybv/pybv/io.py

Lines 210 to 227 in 76e8bea

def _optimize_channel_unit(resolution, unit):
"""Calculate an optimal channel scaling factor and unit."""
exp = np.log10(resolution)
if unit is None:
if exp <= -7:
return resolution / 1e-9, 'nV'
elif exp <= -2:
return resolution / 1e-6, 'µV'
else:
return resolution, 'V'
elif unit == 'V':
return resolution, 'V'
elif unit == 'mV':
return resolution / 1e-3, 'mV'
elif unit in ('µV', 'uV'):
return resolution / 1e-6, 'µV'
elif unit == 'nV':
return resolution / 1e-9, 'nV'

This is the desired behavior for scaling the data at the same time to both (1) from volts to the desired unit, and (2) to the desired resolution. HOWEVER, in the VHDR, the unit and the resolution are noted for each channel. Thus the original resolution prior to going through "optimize_channel_unit" must be written to VHDR

@tstenner do you happen to have time to look into this? 🙂

we should also add a test that does not depend on MNE.

-->

  1. write data to bv given a vector of different resolutions
  2. read the resulting vhdr file with bare python
  3. check that the written and original resolutions match exactly

actually, I am seeing now that we never scale the data to the desired unit. The data is only scaled to the desired resolution in VOLTS, and then written to file.

Then the "resolution" field in vhdr is "abused" to encode both the conversion from volt to the desired unit AND the back-scaling.

This works equivalently, but it's not what the BrainVision spec says. --> the resolution is supposed to be the resolution in units.

Looking at the docstr for resolution I see, that we also require that to be "in volts", instead of in "units" --> so at least we are being consistent there, and it explains why the float32 format roundtrips all pass.

I still think we should change this behavior to be more in line with the BV standard.

And I still have no solution for why the int16 tests fail. #45