MEG source reconstruction and sensor topography don't agree

I do something like mne.compute_rank(inst, tol_kind="relative", tol=1e-3) from whatever data you are using to compute the covariance (e.g., Epochs or Raw) and then pass that rank to both compute_covariance and make_inverse_operator. It should prevent tiny eigenvalues from messing up the whitening step.

4 Likes

Interesting. We should probably adopt this approach in MNE-BIDS-Pipeline, too?

Dear Eric,

Thanks for your suggestion, for some reason I missed your response last week!
I did as you suggested:

rank_noise = mne.compute_rank(er_ICAed, tol_kind="relative", tol=1e-3)
noise_cov = mne.compute_raw_covariance(er_ICAed, tmin=0, tmax=None, rank=rank_noise)

The rank computed with the defined tolerance was 68, smaller than 71 from the default method.

Then:

raw = mne.io.read_raw_fif(raw_fname, allow_maxshield=True, preload=True, verbose=True)
rank_data = mne.compute_rank(raw, tol_kind="relative", tol=1e-3)
inverse_operator = mne.minimum_norm.make_inverse_operator(
    raw.info, fwd, noise_cov, loose='auto', depth=0.8, rank=rank_data
)

I re-calculated the whitened data and the source reconstruction. Although the whitened data still look like the ones above (with weird oscillatory patterns), the source reconstruction now looks much closer to what I expected:

Now that this suggestion seems to alleviate my problem, would you still suggest using the pre-stimulus silence period for computing noise covariance? My consideration for using the empty-room was that my experiment involves listening to the same stimuli under two task conditions, therefore I thought there might be some task-related activity in the prestimulus time that I shouldnā€™t wipe off. But this might not be a good reason after allā€¦

Yaqing

1 Like

Typically, during the experiment youā€™d randomize condition order and jitter the stimulus onset such that the participant wouldnā€™t know which stimulus to expect, and when. This should suppress meaningful (i.e., systematic) baseline activity.

Richard

Thanks again for your prompt answer!

My experiment is a bit atypical in that the two conditions (tasks) are not randomly interleaved but completely separated into two blocks. Therefore, although single trials (sentences) are randomized within each block so participants do not know what exact sentence they will hear next, they do have a different ā€œideaā€ of what they need to do about the sentence for the two blocksā€¦ My hypothesis for the experiment is that they process sentence keywords differently between tasks (in a way similar to priming).

I would assume such an effect on the baseline (prestimulus) period to be very subtle, therefore if the prestimulus period provides a more numerically stable solution to the source reconstruction, I should stick to it for both noise covariance and baseline correction?

Dear Eric,

A follow-up question about your response. I tried re-calculating the covariance and inverse solution by passing the rank parameter as in my first response to you. It did save a few subjectsā€™ source reconstruction. However, for a few other subjects who had ā€œgoodā€ source reconstruction before I applied your trick now have aberrant results as the ā€œbadā€ example I showed in the first post.

I suspect that I didnā€™t understand your method correctly and hope to clarify: did you mean you would 1) compute the rank from the noise (either empty room or inter-trial silence period) and apply it to both conpute_covariance and make_inverse_operator, or 2) compute the rank from the raw data and apply it to both calculations, or 3) use the ranks of noise and raw data separately for the two calculations?

Many thanks,
Yaqing

I assume youā€™d pass the smaller of either (noise cov rank or data rank) in all relevant placesā€¦ :thinking:

2 Likes

Thanks for the answer, this resolves the problem. Now every participantā€™s source reconstruction looks reasonable!

I very much appreciate the help here :slight_smile:

Yaqing

3 Likes

Doing my own sanity check on a similar finding: @yaqing would you mind posting your final code that you found best fit your data?

Hi @pmolfese , I now compute the ranks of my noise (empty room) data and experiment data separately, choose the smaller of the two, and apply it to constrain the calculation of covariance and inverse operator:

rank_er = mne.compute_rank(er_ICAed, tol_kind="relative", tol=1e-3)
rank_raw = mne.compute_rank(raw, tol_kind="relative", tol=1e-3)
rk = np.min([rank_er['meg'], rank_raw['meg']])
rank = {'meg': rk}

noise_cov = mne.compute_raw_covariance(er_ICAed, tmin=0, tmax=None, rank=rank)

inverse_operator = mne.minimum_norm.make_inverse_operator(
  raw.info, fwd, noise_cov, loose='auto', depth=0.8, rank=rank
)

Hope this helps.

Yaqing

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.