Esempio n. 1
0
def test_long_extraction():
    fnirs_data_folder = mne.datasets.fnirs_motor.data_path()
    fnirs_raw_dir = os.path.join(fnirs_data_folder, 'Participant-1')
    raw_intensity = mne.io.read_raw_nirx(fnirs_raw_dir).load_data()

    long_chans = get_long_channels(raw_intensity)

    original_num_channels = len(raw_intensity.ch_names)
    assert original_num_channels == 56

    long_num_channels = len(long_chans.ch_names)
    assert long_num_channels == 56 - 16

    new_lens = source_detector_distances(long_chans.info)
    assert np.min(new_lens) >= 0.01

    # Now test for non standard short length
    long_chans = get_long_channels(raw_intensity, min_dist=0.022)

    long_num_channels = len(long_chans.ch_names)
    assert long_num_channels > 16  # There are 8 SDs in this set * hbo/hbr

    new_lens = source_detector_distances(long_chans.info)
    assert np.max(new_lens) >= 0.022

    # Check that we dont run on other types, eg eeg.
    raw_intensity.pick(picks=range(2))
    raw_intensity.set_channel_types({'S1_D1 760': 'eeg', 'S1_D1 850': 'eeg'},
                                    verbose='error')
    with pytest.raises(RuntimeError, match='NIRS signals only'):
        _ = get_long_channels(raw_intensity)
Esempio n. 2
0
def test_nirx_15_0():
    """Test reading NIRX files."""
    raw = read_raw_nirx(fname_nirx_15_0, preload=True)

    # Test data import
    assert raw._data.shape == (20, 92)
    assert raw.info['sfreq'] == 6.25
    assert raw.info['meas_date'] == dt.datetime(2019,
                                                10,
                                                27,
                                                13,
                                                53,
                                                34,
                                                209000,
                                                tzinfo=dt.timezone.utc)

    # Test channel naming
    assert raw.info['ch_names'][:12] == [
        "S1_D1 760", "S1_D1 850", "S2_D2 760", "S2_D2 850", "S3_D3 760",
        "S3_D3 850", "S4_D4 760", "S4_D4 850", "S5_D5 760", "S5_D5 850",
        "S6_D6 760", "S6_D6 850"
    ]

    # Test info import
    assert raw.info['subject_info'] == {
        'birthday': (2004, 10, 27),
        'first_name': 'NIRX',
        'last_name': 'Test',
        'sex': FIFF.FIFFV_SUBJ_SEX_UNKNOWN,
        'his_id': "NIRX_Test"
    }

    # Test trigger events
    assert_array_equal(raw.annotations.description, ['1.0', '2.0', '2.0'])

    # Test location of detectors
    allowed_dist_error = 0.0002
    locs = [ch['loc'][6:9] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][3:5] == 'D1'
    assert_allclose(mni_locs[0], [0.0287, -0.1143, -0.0332],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][15][3:5] == 'D8'
    assert_allclose(mni_locs[15], [-0.0693, -0.0480, 0.0657],
                    atol=allowed_dist_error)

    # Test distance between optodes matches values from
    allowed_distance_error = 0.0002

    assert_allclose(source_detector_distances(
        raw.copy().pick("S1_D1 760").info), [0.0300],
                    atol=allowed_distance_error)
    assert_allclose(source_detector_distances(
        raw.copy().pick("S7_D7 760").info), [0.0392],
                    atol=allowed_distance_error)
Esempio n. 3
0
def get_long_channels(raw, min_dist=0.01):
    """
    Return channels with a long source detector separation.


    Parameters
    ----------
    raw : instance of Raw
        The haemoglobin data.
    min_dist : number
        Minimum distance of returned channel.

    Returns
    -------
    raw : instance of Raw
        Raw instance with only long channels.
    """

    long_chans = raw.copy().load_data()
    _validate_type(long_chans, BaseRaw, 'raw')

    picks = mne.pick_types(long_chans.info, meg=False, eeg=False, fnirs=True)
    if not len(picks):
        raise RuntimeError('Short channel extraction for NIRS signals only.')

    dists = source_detector_distances(long_chans.info, picks=picks)
    long_chans.pick(picks[dists > min_dist])

    return long_chans
Esempio n. 4
0
def get_short_channels(raw, max_dist=0.01):
    """
    Return channels with a short source-detector separation.

    Parameters
    ----------
    raw : instance of Raw
        Raw instance containing fNIRS data.
    max_dist : number
        Maximum distance of returned channels (m).

    Returns
    -------
    raw : instance of Raw
        Raw instance with only short channels.
    """

    short_chans = raw.copy().load_data()
    _validate_type(short_chans, BaseRaw, 'raw')

    picks = mne.pick_types(short_chans.info,
                           meg=False,
                           eeg=False,
                           fnirs=True,
                           exclude=[])
    if not len(picks):
        raise RuntimeError('Short channel extraction for NIRS signals only.')

    dists = source_detector_distances(short_chans.info, picks=picks)
    short_chans.pick(picks[dists < max_dist])

    return short_chans
def short_channel_regression(raw, max_dist=0.01):
    """
    Systemic correction regression based on nearest short channel.

    Method as described by NIRx and based on
    :footcite:`fabbri2004optical`, :footcite:`saager2005direct`,
    and :footcite:`scholkmann2014measuring`.

    Parameters
    ----------
    raw : instance of Raw
        Raw instance containing optical density data.
    max_dist : number
        Channels less than this distance are considered short (m).

    Returns
    -------
    raw : instance of Raw
        The modified raw instance.

    References
    ----------
    .. footbibliography::
    """
    raw = raw.copy().load_data()
    _validate_type(raw, BaseRaw, 'raw')

    picks_od = pick_types(raw.info, fnirs='fnirs_od')

    if len(picks_od) == 0:
        raise RuntimeError('Data must be optical density.')

    distances = source_detector_distances(raw.info)

    picks_short = picks_od[distances[picks_od] < max_dist]
    picks_long = picks_od[distances[picks_od] > max_dist]

    if len(picks_short) == 0:
        raise RuntimeError('No short channels present.')
    if len(picks_long) == 0:
        raise RuntimeError('No long channels present.')

    for pick in picks_long:

        short_idx = _find_nearest_short(raw, pick, picks_short)

        A_l = raw.get_data(pick).ravel()
        A_s = raw.get_data(short_idx).ravel()

        # Eqn 27 Scholkmann et al 2014
        alfa = np.dot(A_s, A_l) / np.dot(A_s, A_s)

        # Eqn 26 Scholkmann et al 2014
        raw._data[pick] = A_l - alfa * A_s

    return raw
Esempio n. 6
0
def test_long_extraction():
    fnirs_data_folder = mne.datasets.fnirs_motor.data_path()
    fnirs_raw_dir = os.path.join(fnirs_data_folder, 'Participant-1')
    raw_intensity = mne.io.read_raw_nirx(fnirs_raw_dir).load_data()

    long_chans = get_long_channels(raw_intensity)

    original_num_channels = len(raw_intensity.ch_names)
    assert original_num_channels == 56

    long_num_channels = len(long_chans.ch_names)
    assert long_num_channels == 56 - 16

    new_lens = source_detector_distances(long_chans.info)
    assert np.min(new_lens) >= 0.01

    # Now test for non standard short length
    long_chans = get_long_channels(raw_intensity, min_dist=0.022)

    long_num_channels = len(long_chans.ch_names)
    assert long_num_channels > 16  # There are 8 SDs in this set * hbo/hbr

    new_lens = source_detector_distances(long_chans.info)
    assert np.max(new_lens) >= 0.022
Esempio n. 7
0
def test_nirx_15_0():
    """Test reading NIRX files."""
    raw = read_raw_nirx(fname_nirx_15_0, preload=True)

    # Test data import
    assert raw._data.shape == (20, 92)
    assert raw.info['sfreq'] == 6.25

    # Test channel naming
    assert raw.info['ch_names'][:12] == [
        "S1_D1 760", "S1_D1 850", "S2_D2 760", "S2_D2 850", "S3_D3 760",
        "S3_D3 850", "S4_D4 760", "S4_D4 850", "S5_D5 760", "S5_D5 850",
        "S6_D6 760", "S6_D6 850"
    ]

    # Test info import
    assert raw.info['subject_info'] == {
        'first_name': 'NIRX',
        'last_name': 'Test',
        'sex': '0'
    }

    # Test trigger events
    assert_array_equal(raw.annotations.description, ['1.0', '2.0', '2.0'])

    # Test location of detectors
    allowed_dist_error = 0.0002
    locs = [ch['loc'][6:9] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][3:5] == 'D1'
    assert_allclose(mni_locs[0], [0.0287, -0.1143, -0.0332],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][15][3:5] == 'D8'
    assert_allclose(mni_locs[15], [-0.0693, -0.0480, 0.0657],
                    atol=allowed_dist_error)

    # Test distance between optodes matches values from
    allowed_distance_error = 0.0002
    distances = source_detector_distances(raw.info)
    assert_allclose(distances[::2], [
        0.0301, 0.0315, 0.0343, 0.0368, 0.0408, 0.0399, 0.0393, 0.0367, 0.0336,
        0.0447
    ],
                    atol=allowed_distance_error)
Esempio n. 8
0
def test_snirf_nirsport2_w_positions():
    """Test reading SNIRF files with known positions."""
    raw = read_raw_snirf(nirx_nirsport2_103_2,
                         preload=True,
                         optode_frame="mri")

    # Test data import
    assert raw._data.shape == (40, 128)
    assert_almost_equal(raw.info['sfreq'], 10.2, decimal=1)

    # Test channel naming
    assert raw.info['ch_names'][:4] == [
        'S1_D1 760', 'S1_D1 850', 'S1_D6 760', 'S1_D6 850'
    ]
    assert raw.info['ch_names'][24:26] == ['S6_D4 760', 'S6_D4 850']

    # Test frequency encoding
    assert raw.info['chs'][0]['loc'][9] == 760
    assert raw.info['chs'][1]['loc'][9] == 850

    assert sum(short_channels(raw.info)) == 16

    # Test distance between optodes matches values from
    # nirsite https://github.com/mne-tools/mne-testing-data/pull/86
    # figure 3
    allowed_distance_error = 0.005
    distances = source_detector_distances(raw.info)
    assert_allclose(distances[::2][:14], [
        0.0304, 0.0411, 0.008, 0.0400, 0.008, 0.0310, 0.0411, 0.008, 0.0299,
        0.008, 0.0370, 0.008, 0.0404, 0.008
    ],
                    atol=allowed_distance_error)

    # Test location of detectors
    # The locations of detectors can be seen in the first
    # figure on this page...
    # https://github.com/mne-tools/mne-testing-data/pull/86
    allowed_dist_error = 0.0002
    locs = [ch['loc'][6:9] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][3:5] == 'D1'
    assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][2][3:5] == 'D6'
    assert_allclose(mni_locs[2], [-0.0841, -0.0138, 0.0248],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][34][3:5] == 'D5'
    assert_allclose(mni_locs[34], [0.0845, -0.0451, -0.0123],
                    atol=allowed_dist_error)

    # Test location of sensors
    # The locations of sensors can be seen in the second
    # figure on this page...
    # https://github.com/mne-tools/mne-testing-data/pull/86
    allowed_dist_error = 0.0002
    locs = [ch['loc'][3:6] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][:2] == 'S1'
    assert_allclose(mni_locs[0], [-0.0848, -0.0162, -0.0163],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][9][:2] == 'S2'
    assert_allclose(mni_locs[9], [-0.0, -0.1195, 0.0142],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][34][:2] == 'S8'
    assert_allclose(mni_locs[34], [0.0828, -0.046, 0.0285],
                    atol=allowed_dist_error)

    mon = raw.get_montage()
    assert len(mon.dig) == 43
Esempio n. 9
0
def test_nirsport_v2():
    """Test NIRSport2 file."""
    raw = read_raw_nirx(nirsport2, preload=True)
    assert raw._data.shape == (40, 128)

    # Test distance between optodes matches values from
    # nirsite https://github.com/mne-tools/mne-testing-data/pull/86
    # figure 3
    allowed_distance_error = 0.005
    distances = source_detector_distances(raw.info)
    assert_allclose(distances[::2][:14], [
        0.0304, 0.0411, 0.008, 0.0400, 0.008, 0.0310, 0.0411, 0.008, 0.0299,
        0.008, 0.0370, 0.008, 0.0404, 0.008
    ],
                    atol=allowed_distance_error)

    # Test location of detectors
    # The locations of detectors can be seen in the first
    # figure on this page...
    # https://github.com/mne-tools/mne-testing-data/pull/86
    allowed_dist_error = 0.0002
    locs = [ch['loc'][6:9] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][3:5] == 'D1'
    assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][2][3:5] == 'D6'
    assert_allclose(mni_locs[2], [-0.0841, -0.0138, 0.0248],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][34][3:5] == 'D5'
    assert_allclose(mni_locs[34], [0.0845, -0.0451, -0.0123],
                    atol=allowed_dist_error)

    # Test location of sensors
    # The locations of sensors can be seen in the second
    # figure on this page...
    # https://github.com/mne-tools/mne-testing-data/pull/86
    locs = [ch['loc'][3:6] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][:2] == 'S1'
    assert_allclose(mni_locs[0], [-0.0848, -0.0162, -0.0163],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][9][:2] == 'S2'
    assert_allclose(mni_locs[9], [-0.0, -0.1195, 0.0142],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][34][:2] == 'S8'
    assert_allclose(mni_locs[34], [0.0828, -0.046, 0.0285],
                    atol=allowed_dist_error)

    assert len(raw.annotations) == 3
    assert raw.annotations.description[0] == '1.0'
    assert raw.annotations.description[2] == '6.0'
    # Lose tolerance as I am eyeballing the time differences on screen
    assert_allclose(np.diff(raw.annotations.onset), [2.3, 3.1], atol=0.1)

    mon = raw.get_montage()
    assert len(mon.dig) == 43
Esempio n. 10
0
def test_nirx_15_3_short():
    """Test reading NIRX files."""
    raw = read_raw_nirx(fname_nirx_15_3_short, preload=True)

    # Test data import
    assert raw._data.shape == (26, 220)
    assert raw.info['sfreq'] == 12.5

    # Test channel naming
    assert raw.info['ch_names'][:4] == [
        "S1_D2 760", "S1_D2 850", "S1_D9 760", "S1_D9 850"
    ]
    assert raw.info['ch_names'][24:26] == ["S5_D13 760", "S5_D13 850"]

    # Test frequency encoding
    assert raw.info['chs'][0]['loc'][9] == 760
    assert raw.info['chs'][1]['loc'][9] == 850

    # Test info import
    assert raw.info['subject_info'] == dict(birthday=(2020, 8, 18),
                                            sex=0,
                                            first_name="testMontage\\0A"
                                            "TestMontage",
                                            his_id="testMontage\\0A"
                                            "TestMontage")

    # Test distance between optodes matches values from
    # https://github.com/mne-tools/mne-testing-data/pull/72
    allowed_distance_error = 0.001
    distances = source_detector_distances(raw.info)
    assert_allclose(distances[::2], [
        0.0304, 0.0078, 0.0310, 0.0086, 0.0416, 0.0072, 0.0389, 0.0075, 0.0558,
        0.0562, 0.0561, 0.0565, 0.0077
    ],
                    atol=allowed_distance_error)

    # Test which channels are short
    # These are the ones marked as red at
    # https://github.com/mne-tools/mne-testing-data/pull/72
    is_short = short_channels(raw.info)
    assert_array_equal(is_short[:9:2], [False, True, False, True, False])
    is_short = short_channels(raw.info, threshold=0.003)
    assert_array_equal(is_short[:3:2], [False, False])
    is_short = short_channels(raw.info, threshold=50)
    assert_array_equal(is_short[:3:2], [True, True])

    # Test trigger events
    assert_array_equal(raw.annotations.description, ['4.0', '2.0', '1.0'])

    # Test location of detectors
    # The locations of detectors can be seen in the first
    # figure on this page...
    # https://github.com/mne-tools/mne-testing-data/pull/72
    # And have been manually copied below
    allowed_dist_error = 0.0002
    locs = [ch['loc'][6:9] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][3:5] == 'D2'
    assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][4][3:5] == 'D1'
    assert_allclose(mni_locs[4], [0.0846, -0.0142, -0.0156],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][8][3:5] == 'D3'
    assert_allclose(mni_locs[8], [0.0207, -0.1062, 0.0484],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][12][3:5] == 'D4'
    assert_allclose(mni_locs[12], [-0.0196, 0.0821, 0.0275],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][16][3:5] == 'D5'
    assert_allclose(mni_locs[16], [-0.0360, 0.0276, 0.0778],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][19][3:5] == 'D6'
    assert_allclose(mni_locs[19], [0.0388, -0.0477, 0.0932],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][21][3:5] == 'D7'
    assert_allclose(mni_locs[21], [-0.0394, -0.0483, 0.0928],
                    atol=allowed_dist_error)
Esempio n. 11
0
def test_nirx_15_2_short():
    """Test reading NIRX files."""
    raw = read_raw_nirx(fname_nirx_15_2_short, preload=True)

    # Test data import
    assert raw._data.shape == (26, 145)
    assert raw.info['sfreq'] == 12.5
    assert raw.info['meas_date'] == dt.datetime(2019,
                                                8,
                                                23,
                                                7,
                                                37,
                                                4,
                                                540000,
                                                tzinfo=dt.timezone.utc)

    # Test channel naming
    assert raw.info['ch_names'][:4] == [
        "S1_D1 760", "S1_D1 850", "S1_D9 760", "S1_D9 850"
    ]
    assert raw.info['ch_names'][24:26] == ["S5_D13 760", "S5_D13 850"]

    # Test frequency encoding
    assert raw.info['chs'][0]['loc'][9] == 760
    assert raw.info['chs'][1]['loc'][9] == 850

    # Test info import
    assert raw.info['subject_info'] == dict(sex=1,
                                            first_name="MNE",
                                            middle_name="Test",
                                            last_name="Recording",
                                            birthday=(2014, 8, 23),
                                            his_id="MNE_Test_Recording")

    # Test distance between optodes matches values from
    # nirsite https://github.com/mne-tools/mne-testing-data/pull/51
    # step 4 figure 2
    allowed_distance_error = 0.0002
    distances = source_detector_distances(raw.info)
    assert_allclose(distances[::2], [
        0.0304, 0.0078, 0.0310, 0.0086, 0.0416, 0.0072, 0.0389, 0.0075, 0.0558,
        0.0562, 0.0561, 0.0565, 0.0077
    ],
                    atol=allowed_distance_error)

    # Test which channels are short
    # These are the ones marked as red at
    # https://github.com/mne-tools/mne-testing-data/pull/51 step 4 figure 2
    is_short = short_channels(raw.info)
    assert_array_equal(is_short[:9:2], [False, True, False, True, False])
    is_short = short_channels(raw.info, threshold=0.003)
    assert_array_equal(is_short[:3:2], [False, False])
    is_short = short_channels(raw.info, threshold=50)
    assert_array_equal(is_short[:3:2], [True, True])

    # Test trigger events
    assert_array_equal(raw.annotations.description, ['3.0', '2.0', '1.0'])

    # Test location of detectors
    # The locations of detectors can be seen in the first
    # figure on this page...
    # https://github.com/mne-tools/mne-testing-data/pull/51
    # And have been manually copied below
    # These values were reported in mm, but according to this page...
    # https://mne.tools/stable/auto_tutorials/intro/plot_40_sensor_locations.html
    # 3d locations should be specified in meters, so that's what's tested below
    # Detector locations are stored in the third three loc values
    allowed_dist_error = 0.0002
    locs = [ch['loc'][6:9] for ch in raw.info['chs']]
    head_mri_t, _ = _get_trans('fsaverage', 'head', 'mri')
    mni_locs = apply_trans(head_mri_t, locs)

    assert raw.info['ch_names'][0][3:5] == 'D1'
    assert_allclose(mni_locs[0], [-0.0841, -0.0464, -0.0129],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][4][3:5] == 'D3'
    assert_allclose(mni_locs[4], [0.0846, -0.0142, -0.0156],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][8][3:5] == 'D2'
    assert_allclose(mni_locs[8], [0.0207, -0.1062, 0.0484],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][12][3:5] == 'D4'
    assert_allclose(mni_locs[12], [-0.0196, 0.0821, 0.0275],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][16][3:5] == 'D5'
    assert_allclose(mni_locs[16], [-0.0360, 0.0276, 0.0778],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][19][3:5] == 'D6'
    assert_allclose(mni_locs[19], [0.0352, 0.0283, 0.0780],
                    atol=allowed_dist_error)

    assert raw.info['ch_names'][21][3:5] == 'D7'
    assert_allclose(mni_locs[21], [0.0388, -0.0477, 0.0932],
                    atol=allowed_dist_error)
Esempio n. 12
0
def short_channel_regression(raw, max_dist=0.01):
    """
    Short channel regression based on nearest channel.

    Fabbri, Francesco, et al. "Optical measurements of absorption changes in
    two-layered diffusive media."
    Physics in Medicine & Biology 49.7 (2004): 1183.

    Saager, Rolf B., and Andrew J. Berger. "Direct characterization and
    removal of interfering absorption trends in two-layer turbid media."
    JOSA A 22.9 (2005): 1874-1882.

    Scholkmann, Felix, Andreas Jaakko Metz, and Martin Wolf.
    "Measuring tissue hemodynamics and oxygenation by continuous-wave
    functional near-infrared spectroscopy—how robust are the different
    calculation methods against movement artifacts?."
    Physiological measurement 35.4 (2014): 717.

    Parameters
    ----------
    raw : instance of Raw
        Haemoglobin data.
    max_dist : number
        Channels less than this distance are considered short (m).

    Returns
    -------
    raw : instance of Raw
        The modified raw instance.
    """
    raw = raw.copy().load_data()
    _validate_type(raw, BaseRaw, 'raw')

    picks_od = pick_types(raw.info, fnirs='fnirs_od')

    if len(picks_od) == 0:
        raise RuntimeError('Data must be optical density.')

    distances = source_detector_distances(raw.info)

    picks_short = picks_od[distances[picks_od] < max_dist]
    picks_long = picks_od[distances[picks_od] > max_dist]

    if len(picks_short) == 0:
        raise RuntimeError('No short channels present.')
    if len(picks_long) == 0:
        raise RuntimeError('No long channels present.')

    for pick in picks_long:

        short_idx = _find_nearest_short(raw, pick, picks_short)

        A_l = raw.get_data(pick).ravel()
        A_s = raw.get_data(short_idx).ravel()

        # Eqn 27 Scholkmann et al 2014
        alfa = np.dot(A_s, A_l) / np.dot(A_s, A_s)

        # Eqn 26 Scholkmann et al 2014
        raw._data[pick] = A_l - alfa * A_s

    return raw