-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] Enable averaging connectivity over tapers instead of averaging PSD over tapers #84
Comments
mne-connectivity/mne_connectivity/spectral/time.py Lines 269 to 282 in 711ccce
These lines possibly are contributing to the discrepancy we see. Before, we were averaging multi taper analysis across tapers before we computed connectivity. We should instead be computing connectivity for all tapers and then averaging. |
@adam2392 Is there a regression test that already covers this? Because I commented out 276,277 and uncommented 281,282 and all tests seem to pass.. If not, I could try writing a regression test and checking it out.. |
No unfortunately there is not. The issue that made it not a "trivial fix" is that the conn_func needs to be applied for each taper, but right now the API doesn't support doing something like that. I would first identify what pieces of code need to change and propose a quick pseudocode here to see if it makes sense. |
I'm currently working on this issue and probably have already solved it, barring testing. |
Sure sounds good! @ruuskas lmk if there's a PR you would like help iterating on. I can suggest help for testing if needed. |
Awesome excited to see the PR! Feel free to start it early as a "WIP" Draft. |
@adam2392 I have submitted the PR. Could you have a look when you have time? |
Hi @adam2392, @larsoner. I came back to this after finding some quite peculiar behaviour with the connectivity function. Are you sure that this conclusion is correct?
I did some testing with this, and the connectivity results do not appear smooth at all. See plots below. Most importantly, there's a dip in connectivity at 10Hz, which is the only actual coupling frequency in the simulated data. Morlet convolution for comparison. These were computed with the implementation found in #104. I'm just guessing, but perhaps the cross-spectral density should be averaged and connectivity computed from that instead of averaging connectivity matrices? I will go through the code tomorrow to check for other potential bugs that could cause this. |
In principle yes it seems like a reasonable conclusion to me. I agree that the first plot looks buggy, though -- I wouldn't expect it to look like that. Have you tried using multitaper with exactly one taper? That should look more like the |
Hi @larsoner. I tried doing what you suggested. Indeed, the second taper is not smooth, nor is the third. I also plotted the (absolute value of the) CSD computed from the output of The simulated data in this case is a 10Hz sinusoid with amplitude 0.3 and random but constant phase in each channel, with uniformly random additive noise. |
Here's a comparison between the three different ways to average the tapers. Namely, averaging connectivity matrices, averaging the complex signal, and averaging the CSD. I plotted five different connectivity metrics against frequency. The underlying signal in the simulated channels is a 10Hz phase-locked sinusoid with additive noise. It looks like averaging the CSD would give the smoothest result. This conclusion appears to be supported by the formulation in Wikipedia. WDYT? |
In the "average connectivity" case, is it a weighted average? I think it needs to be in order to be comparable. A naive/simple average would unfairly bias the results to the tapes with less power compared to the average-complex and average-CSD cases (which implicitly include the weighting IIUC). |
... but in any case, from thinking about it briefly it seems like the CSD case could very well in principle be the best choice. Any spectral modification imposed by the window function will occur on both the X and Y signals, but this should go away during CSD computation because it effectively only looks at relative amplitude and phase (compared to the average-complex-signals case where any phase shifts across tapers will be combined/averaged rather than removed before averaging). And as you point out this quote makes it clear:
So +1 for using averaged PSD. I'm still curious about the weighted vs unweighted average in the above plots, but even if these are unweighted, I'm guessing the weighted average will not look as reasonable (or be as correct in principle!) as the average CSD case. |
@ruuskas can you plot the tapers themselves to see if they look right? I would expect something like this (blue, orange, green are the first 3): |
This was just the simple average without any weighting. How should one go about computing the weights? I would assume that the weights should be frequency specific.
I see. I could add this in the PR where I'm already suggesting several changes to |
Usually taper-specific. They are related to the eigenvalues from the eigen decomp that computes the tapers, see for example We should already use them in MNE-Python when computing PSDs. In addition to potentially being useful for your comparison above, we should probably use them when averaging the CSDs across tapers just like we do for PSDs. |
Just to be sure we're on the same page, the results above were computed using the complex signal output from |
I think any time you combine estimates from multiple tapers, you probably want to use a weighted average rather than a naive/uniform average. So assuming your |
In # Get dpss tapers
tapers, conc = dpss_windows(t.shape[0], time_bandwidth / 2.,
n_taps, sym=False)
Wk = oscillation * tapers[m]
if zero_mean: # to make it zero mean
real_offset = Wk.mean()
Wk -= real_offset
Wk /= np.sqrt(0.5) * np.linalg.norm(Wk.ravel()) I will try computing the weights and post the connectivity plots here anyway. EDIT: Tagging @agramfort here as well as you seem to be one of the authors of |
Here is the figure including the weighted average of CSD. The weights are very close to one, rendering their effect miniscule. |
+1 for using the weighted average since I think in principle it's more correct, and consistent with how we do PSDs |
I will add this to #104. |
As of v1.0 MNE-Python, there was a bug fix to not average the
tfr
in multitaper analysis unless the user specified. So using that in mne-connectivity, we need to compute the power in multiple tapers, and then compute connectivity and then average across tapers.I see. Thanks for this comment. Perhaps that is why there are some issues in #73
Originally posted by @adam2392 in #82 (comment)
The text was updated successfully, but these errors were encountered: