bids-standard / pybv

A lightweight I/O utility for the BrainVision data format, written in Python.
https://pybv.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
21 stars 13 forks source link

Let pybv write [coordinates] section to vhdr files #44

Open sappelhoff opened 4 years ago

sappelhoff commented 4 years ago

See BrainVision data file specification.

The OPTIONAL [Coordinates] section in a vhdr file comes right after the REQUIRED [Channels] section, and it looks like this:

[Coordinates]
; Each entry: Ch<Channel number>=<Radius>,<Theta>,<Phi>
Ch1=1,-60,-51
Ch2=1,-49,-29
Ch3=1,-45,0
Ch4=1,-49,29

For the radius, the spec say the following [emphasis by me]:

“The radius r specifies the distance (in millimeters) between point P and the origin of the coordinate system. The only exceptions are r = 0 and r = 1. r = 0 signifies an invalid position, for instance when the position of an electrode is not known. When realistic electrode coordinates are used, r can have a different value for each channel. In other cases, the value of r should be the same for all the channels if a spherical head model is used. For instance, in the Analyzer's standard coordinate system, r = 1”.

All coordinates that pybv writes to the [Coordinates] section must first be transformed to the Analyzer's standard coordinate system, which happens to be the CapTrak system (more info in FieldTrip wiki). For this conversion to work, we will need the Nasion, left, and right preauricular point coordinates (to rescale the coordsystem).

I suggest that furthermore, pybv writes a more extensive comment in the [Coordinates] section:

[Coordinates]
; Each entry: Ch<Channel number>=<Radius>,<Theta>,<Phi>
; Radius defined in millimeters (mm).
; Radius of 0 signifies invalid position for a given electrode.
; If all coordinates are on an (idealized) spherical head model, Radius will be 1 for all entries.
; The coordinate system is "Captrak", see definition of axes below.
; The X-axis goes from the left preauricular point towards (through) the right preauricular point.
; The Y-axis goes orthogonally to the X-axis and towards (through) the nasion.
; The Z-axis goes orthogonally to the X-Y-plane upwards.
; Below are the coordinates for left and right preauricular points, and the nasion.
; LPA=1,44,55
; RPA=1,44,55
; Nasion=1,44,55
Ch1=1,-60,-51
Ch2=1,-49,-29
Ch3=1,-45,0
Ch4=1,-49,29
sappelhoff commented 3 years ago

this will be particularly interesting once MNE starts to export to pybv ... because we'll want to capture as much of the FIF data as possible for a round-trip.

sappelhoff commented 3 years ago

as discussed in #77, the input for a coordinates parameter in write_brainvision could be a list of dicts:

[
    {
        "name": "LPA",
        "x": 0.3,
        "y": 4.5,
        "z": 6.1,
    },
    {
        "name": "Fpz",
        "radius": 3.1,
        "theta": 22,
        "phi": 33,
    }
]

pybv would then:

PS: I have a very lengthy email discussion on this topic with Brain Products that I didn't post here ... But I think what we plan here would be spec conformant: Especially if we put coordsystem info, units, and landmarks as "comments".

BV Readers can then optionally check the VHDR for whether the file was created by "pybv" and if it was, make use of that "comment".

BV Readers that dont check for that, will still get sensible data: At least as sensible as the underspecified "Coordinates" section allows :-)

hoechenberger commented 3 years ago

This sounds great!

sappelhoff commented 2 years ago

we'd probably need to look at these three functions in mne

and simplify them for use here without adding mne as a dependency.