Skip to content
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

Re-referencing concerns #134

Open
Andesha opened this issue Jun 8, 2023 · 9 comments
Open

Re-referencing concerns #134

Andesha opened this issue Jun 8, 2023 · 9 comments

Comments

@Andesha
Copy link
Contributor

Andesha commented Jun 8, 2023

This is just a concern, but I've been working a lot more handson with data coming from the pipeline and am not sure that after we are rejecting a source (channels) that we are rereferencing the data.

I see that there's a function for it for channels here but it does not appear to be used after things like the rank channel are thrown out...

@Andesha
Copy link
Contributor Author

Andesha commented Jun 8, 2023

Poking through a bit more of the code it seems like it's done via the get_epochs function - can someone just confirm this is being done correctly?

@scott-huberty
Copy link
Member

I accidentally deleted my response. I'll post it again:

robust average re-referencing happens anytime get_epochs is called:

def get_epochs(self, detrend=None, preload=True, rereference=True,
picks='eeg'):

Here:

if rereference:
    self.flags["ch"].rereference(epochs)

MOST pipeline steps will call get_epochs before starting, thus average re-referencing the data, excluding any channels that are in pipeline.flags['ch'] or pipeline.raw.info['bads'] from the average.

The exceptions are flag_ch_bridge and flag_ch_rank:

# 6. calculate nearest neighbort r values
data_r_ch = self.flag_ch_low_r(message="Flagging uncorrelated"
" channels")
# 7. Identify bridged channels
self.flag_ch_bridge(data_r_ch,
message="Flagging Bridged channels")
# 8. Flag rank channels
self.flag_ch_rank(data_r_ch,
message="Flagging the rank channel")
# 9. Calculate nearest neighbour R values for epochs
self.flag_epoch_low_r(message="Flagging Uncorrelated epochs")

above, flag_ch_low_r calls get_epochs. At the end of it's funciton it returns the 2D matrix of nearest neighbour values that it operated on, which we call data_r_ch.

flag_ch_bridge and flag_ch_rank operate on data_r_ch directly so they don't themselves call get_epochs and thus the data is NOT robust average re-referenced before.

The next time robust average referencing occurs is flag_epoch_low_r, which calls get_epochs.

@Andesha @jadesjardins if this deviates from the MATLAB code, let us know.

@jadesjardins
Copy link

The pipeline was designed to re-reference after every identification of bad channels. flag_chan_bridge is a detection of bad channels so should be followed by re-referencing (excluding the marked channels). The rank channel is not an artifact detection, and the channel flagged by flag_ch_rank should not be removed from the scalp channels. The rank channel remains in the scalp channel data, but this channel is not included in the ICA decomposition. Re-referencing after identifying the rank channel should not do anything because this channel is not marked for rejection (the average reference would be identical to before marking the rank channel).

@scott-huberty
Copy link
Member

scott-huberty commented Jun 14, 2023

Thanks @jadesjardins !

From what I can tell, MATLAB lossless didn't re-reference directly after flag_ch_low_r, or afterflag_ch_bridged , either :

Looking at the MATLAB code and my description of pylossless above, it seems like we directly translated the MATLAB code.

Maybe this was a bug in MAT Lossless that we ported over to Python. But when I think about it, we exclude channels from the average so that noisy channels don't skew the ref. Bridged channels don't quite fit that bill I don't think, so I'm not sure how much of an impact adding another re ref would have. I kind of feel the same about low_r chans.

Unless you feel strongly that skipping the re-ref was a bug that pyLossless should correct (or unless I'm reading the matlab code incorrectly) I'm tempted to consider this a feature request and not a bug fix.

In that case I'm definitely +1 to add another re-reference if others think it's important, but personally I won't have time to do it I don't think. but if anyone is really pressing for this step and implements it in their local fork, a PR is welcome

@scott-huberty
Copy link
Member

The rank channel remains in the scalp channel data, but this channel is not included in the ICA decomposition.

We are excluding rank_channel from following pipeline steps such as flag_epoch_low_r, so I think I'd consider this part a bug and something we should fix.

@Andesha
Copy link
Contributor Author

Andesha commented Jun 14, 2023

I'm pretty sure it does the rereference in the snippet you linked here:

image

@scott-huberty
Copy link
Member

I'm pretty sure it does the rereference in the snippet you linked here:

Totally, but this is done after finishing flagging low_r, bridged, and rank channels in one go. This is the same thing we do in pylossless.

@Andesha
Copy link
Contributor Author

Andesha commented Jun 14, 2023

@jadesjardins ?

@jadesjardins
Copy link

I have not looked at the Matlab lossless scripts in a long time... and I could definitely picture that the re-referencing would only happen at the end of a sequence of channel flagging procedures in a row. That being said, I would recommend implementing the feature of re-referencing after every channel rejection flagging procedure individually. I agree that it is likely to have little impact (so can be low priority), but it would be the correct thing to do.

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

No branches or pull requests

3 participants