Skip to content

Conversation

@mcaffini
Copy link

I started a tutorial to process fNIRS data. It's super basic so this is definitely WIP, but we can work it out together to align this to the other tutorials and to add features of potential interest.

For now, the numpy file with test data can be found here, but we could make use of a public dataset as @agramfort previously suggested.

@codecov-io
Copy link

codecov-io commented May 10, 2017

Codecov Report

Merging #4257 into master will decrease coverage by 0.1%.
The diff coverage is n/a.

@@            Coverage Diff            @@
##           master   #4257      +/-   ##
=========================================
- Coverage    86.2%   86.1%   -0.11%     
=========================================
  Files         346     346              
  Lines       64639   64639              
  Branches     9907    9907              
=========================================
- Hits        55725   55660      -65     
- Misses       6197    6266      +69     
+ Partials     2717    2713       -4

Copy link
Member

@larsoner larsoner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a good start, thanks for working on this


import mne

raw_ndarray = np.load('/home/matteo/raw_ndarray.npy')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make a PR to add this to mne.datasets.misc here? It will be necessary for CircleCI to run, and for anybody to run your tutorial.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcaffini what did you have to do to get this file? there is no real file format? what would an MNE user have to do to get such a file?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, @Eric89GXL that would be an option. If @agramfort still prefers a public dataset, I'll stick with him and adapt the tutorial.
BTW, the real file format is a csv file with fluences data, I manually crunched it to get HbO and HbR concentrations and then saved it in numpy format.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth going from the raw CSV data, then.

Copy link
Author

@mcaffini mcaffini May 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK then

# Usually in fNIRS one looks for brain responses to external sensorial
# stimulations (visual, acoustic, etc.). In order to do so, block design
# studies are usually employed and data are later epoched to get evoked
# responses.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be good to put in the triple-quoted section above.

# fNIRS raw data come in various formats and the best way to dive into MNE is
# to deal with your own format first and fit your data into a 2D numpy array
# [channels x samples]. Once you prepared your time series for HbO and HbR
# concentrations, you can create a RawArray instance from the data array using
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see other tutorials -- you can/should do

:class:`mne.io.RawArray`

and the like to make nice links for people. And then you don't even need the tail end of the sentence here "using mne.io.RawArray"

#
# In this tutorial, I don't preprocess the data. If your fNIRS device outputs
# data in the form of photon fluences at detectors, you can compute HbO and HbR
# concentrations using the modified Lambert-Beer model.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide some link either to a paper (in References section) or e.g. Wikipedia?

# concentrations using the modified Lambert-Beer model.
#
# In the following example we have data from 20 channels plus one events
# channel and we end up # with 20 HbO time series, 20 HbR time series and one
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errant #

raw_data.filter(l_freq, h_freq)

###############################################################################
# In order to have a general glimpse of the dataset, I start by plotting all
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use first-person plural "we" or second-person "you"

scalings = dict(hbo=10e-6, hbr=10e-6, stim=1)
fig_title = 'fNIRS Raw Bandpass filtered [' + str(l_freq) + ' Hz, '
+ str(h_freq) + ' Hz]'
plot_colors = dict(hbo='r', hbr='b', stim='k')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should just change the default colors in raw.plot. Are these standard colors for fNIRS?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, red for HbO and blue for HbR are accepted standards.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay we should change the defaults in raw.plot, then.

# events data using red, blue and black respectively. I also mark color-coded
# events positions, using the same colors previously used in
# mne.viz.plot_events.
scalings = dict(hbo=10e-6, hbr=10e-6, stim=1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again about standardization -- are these standard for fNIRS?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly standard, but reasonable. Signal dynamics may be affected by for many factors such as stimuli type, skull thickness, superficial artifacts, ...

###############################################################################
# I can later dive into the dataset and look at the raw time series more
# closely. Same color-codes through the plots is usually a good idea.
scalings = dict(hbo=10e-6, hbr=10e-6, stim=1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to redefine

# I can later dive into the dataset and look at the raw time series more
# closely. Same color-codes through the plots is usually a good idea.
scalings = dict(hbo=10e-6, hbr=10e-6, stim=1)
fig_title = 'fNIRS Raw Bandpass filtered [' + str(l_freq) + ' Hz, '
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we usually use % pattern like 'fNIRS raw bandpass filtered %s Hz - %s Hz' % (l_freq, h_freq)

#'hbo' or 'hbr' channel type to your channel.
nChannels = 20 # number of physical channels
sampling_frequency = 15.625
channel_names_fnirs = ['HbO '+"%.2d" % i for i in range(1,nChannels+1)] +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"HbO %.2d" % i

is enough

@agramfort
Copy link
Member

agramfort commented May 11, 2017 via email

@agramfort
Copy link
Member

agramfort commented May 11, 2017 via email

@mcaffini
Copy link
Author

I integrated most of the comments, I still have to work on the raw file load-parse-crunch part.

# :func:`mne.viz.plot_events`.
scalings = dict(hbo=10e-6, hbr=10e-6, stim=1)
fig_title = 'fNIRS Raw Bandpass filtered [' + str(l_freq) + ' Hz, ' +
str(h_freq) + ' Hz]'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use %s and not str +

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like just below

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ops sorry fixing this now

# We can later dive into the dataset and look at the raw time series more
# closely. Same color-codes through the plots is usually a good idea.
fig_title = 'fNIRS raw bandpass filtered %s Hz - %s Hz' % (l_freq, h_freq)
plot_colors = dict(hbo='r', hbr='b', stim='k')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update these (and possibly the scalings) here:

https://github.com/mne-tools/mne-python/blob/master/mne/defaults.py#L13

We should probably explicitly pick some aesthetically nice red/blue from here instead of using 'r' and 'b' (which change from 1.+ -> 2.+ of mpl):

https://cloud.githubusercontent.com/assets/11820627/19903655/9ec8a21e-a02c-11e6-8778-80c2f2c068fb.png

# events data using red, blue and black respectively. We also add color-coded
# events positions, using the same colors previously used in
# :func:`mne.viz.plot_events`.
scalings = dict(hbo=10e-6, hbr=10e-6, stim=1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And assuming you're using what can be considered a standard processing setup with standard signals, let's fix the scalings in the same file. We can add it to whats_new.rst as a bugfix.

Use MNE with fNIRS data
=======================

MNE Python was implemented with EEG and MEG in mind, but can be useful to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

originally implemented

(nowadays we try to implement things with a broader scope)

=======================

MNE Python was implemented with EEG and MEG in mind, but can be useful to
process fNIRS data as #well. A common fNIRS data set (similarly to EEG and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no #

@@ -0,0 +1,123 @@
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change filename to plot_fnirs_data.py, and add it to the documentation.rst somewhere.

@larsoner
Copy link
Member

@mcaffini how are we doing here? Any chance you can work on this in the next week or so? We're working on pushing out a release soon and it would be great to have this tutorial

@mcaffini
Copy link
Author

mcaffini commented Sep 5, 2017

Hi @larsoner and sorry for the late reply, I was off work for a long time. Yes, let's finish this in the next days.

@agramfort
Copy link
Member

@mcaffini do you still plan to complete this?

@mcaffini
Copy link
Author

Oops I've seen this just now, sorry.

@agramfort
Copy link
Member

agramfort commented Jun 29, 2018 via email

@larsoner
Copy link
Member

@mcaffini any time for this in the near future? If not, I know another fNIRS person who might be able to take over

@mcaffini
Copy link
Author

@larsoner I can't make it in the near future and I'd be happy if someone takes over :-)

@larsoner
Copy link
Member

@mcaffini do you have the original raw data (light intensity measurements) that were used to generate the chroma concentrations (HBo / HBr)? It would be best if we could also add code to do this processing step, and having the original data + knowing what you did to convert it would help.

@mcaffini
Copy link
Author

@larsoner that specific dataset was exported from our fNIRS device in the form of HbO and HbR concentrations. The conversion from raw intensity to concentration depends on the type of instrument, for CW (continuous-wave) it can be a simple modified Lambert-Beer model, but for FD (frequency-domain) and TD (time-domain) it may be more complicated.
If you think the intensity2concentration step is of interest for MNE Python, my suggestion is to discuss it independently. Eventually all type of intensity data will be converted into concentrations and, after that step, they can benefit from what is discussed here.

@cbrnr
Copy link
Contributor

cbrnr commented Mar 29, 2019

IMO it is sufficient to start from HbO/HbR signals because this is what most devices spit out.

@larsoner
Copy link
Member

Thoughts @rob-luke ?

@rob-luke
Copy link
Member

rob-luke commented Apr 1, 2019

I agree with @mcaffini that the complexity of converting from intensity to concentration is dependent on the type of instrument. And its interesting to hear from @cbrnr that the majority of devices directly export HbO/HbR, are you in an engineering heavy field? or is this in general?

My experience is predominantly in the auditory domain. All the devices I have used are CW and export raw intensity. The devices I have interacted with are NIRX (Macquarie Uni, Bionics Institute, U California), TechEn (NIJT), and Hitachi (UCL). I also attended the last sfNIRS conference and most of the research I saw had to deal with this conversion to concentration. Perhaps the reason I have seen lots of intensity exporting machines is that I am working in less engineering heavy domains, and these CW machines may be cheaper.

I think if you want MNE fNIRS analysis to be available to as many users as possible starting with a CW intensity to concentration conversion step sounds like a good plan. @mcaffini suggestion to split this discussion to a different issue makes sense to me.

@cbrnr
Copy link
Contributor

cbrnr commented Apr 2, 2019

I've worked with fNIRS signals in the BCI field occasionally, but I'm by no means an expert. Maybe the signals I received were even preprocessed, I'm not sure. It sounds like a conversion step is definitely necessary.

@rob-luke
Copy link
Member

rob-luke commented Apr 5, 2019

As a first step to getting HbO/HbR I will raise a PR to read NIRX files. Then we can worry about the conversion steps. We can move this discussion when I open the PR.

@larsoner
Copy link
Member

larsoner commented Apr 5, 2019

Sounds good to me.

@rob-luke rob-luke mentioned this pull request Aug 19, 2019
10 tasks
@larsoner
Copy link
Member

Closing in favor of #6674

@larsoner larsoner closed this Sep 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants