Skip to content

2.4. EEG polarity checks

Below we apply three methods to flag possible reversed EEG polarity, all based on some expected properties of typical (human) NREM sleep, in which we leverage either:

  • the asymmetry in spectral content of positive and negative EEG components

  • the asymmetry of the NREM slow oscillations, based on the duration of negative versus positive halfwaves

  • the typical timing of spindles relative to the phase of slow oscillations

These are heuristics that may not work in all populations or EEG montages, etc, so you may want to do some exploratory work if resolving phase is important to your research question (many analyses of the sleep EEG do not depend on polarity of the signal). The good news is that it is easy to generate flipped signals, and then see if the methods are able to recover who is versus who isn't flipped.

As a reminder, we flipped the sign of all EEG signals for two individuals, F07 and F09. EEG polarity flips can occur because of incorrect re-referencing, etc. Certainly in the case of standard, limited-montage polysomnography, it is not unusual to observe flipped EEGs.


To speed up this demonstration, here we restrict analyses to two channels only, C3 and C4. This is the Luna script we'll use that supports all three approaches above, here constrained to just the two signals (set via the variable s):

luna harm1.lst  s=C3,C4 -o out.db \
 -s ' MASK ifnot=N2,N3
      RE
      FILTER sig=${s} bandpass=0.3,18 tw=1 ripple=0.02
      CHEP-MASK sig=${s} ep-th=3
      CHEP sig=${s} epochs
      RE
      POL sig=${s}
      SPINDLES sig=${s} fc=15 so mag=2 all-spindles ignore-neg-peak nreps=1000 '

In brief,

  • this retains only N2 and N3 epochs

  • it then band-pass filters the EEG, between 0.3 and 18 Hz

  • we remove likely aberrant epochs with the CHEP-MASK and CHEP commands (that are more than 3 SD units from the mean for that channel, in terms of any of the three Hjorth parameters; you will learn more about it in the following section on the artifact removal)

  • we then run a special POL heuristic based on the different spectral content of positive and negative components of the EEG during NREM sleep (for typical scalp electrodes)

  • we then detect fast (target frequency of 15Hz) spindles and slow oscillations using the SPINDLES command

  • specifically, adding SPINDLES so estimates the mean phase angle for slow/delta oscillation at fast (15 Hz) spindle peaks

  • and adding SPINDLES so also outputs the average duration of positive and negative slow oscillation half-waves

The main Luna documentation can give more information on how spindles and SO are detected. Of note here, we pass ignore-neg-peak as an option that impacts how SO are detected, i.e. we don't want to assume we know the correct polarity here, and some heuristics impose thresholds differentially for positive and negative SO halfwaves.

Method 1: spectral content

We extratct two summary statistics from the POL command for each individual/channel:

destrat out.db +POL -r CH -v T_DIFF T_H1 > tmp/pol.1

Method 2: SO morphology

We extract the average duration of positive and negative SO halfwaves:

destrat out.db +SPINDLES -r CH -v SO_DUR SO_DUR_POS SO_DUR_NEG > tmp/pol.2

Method 3: spindle/SO phase coupling angle

We extract the average phase angle of spindle peaks with respect to the slow/delta rhythm:

destrat out.db +SPINDLES -r F CH -v COUPL_ANGLE  > tmp/pol.3

We'll analyse these outputs in R:

p1 <- read.table("tmp/pol.1", header=T, stringsAsFactors=F) 
p2 <- read.table("tmp/pol.2", header=T, stringsAsFactors=F) 
p3 <- read.table("tmp/pol.3", header=T, stringsAsFactors=F)  

Perhaps confusingly, the T statistic from POL is oriented such that (large) positive values imply a (possible/likely) flipped polarity. We'll plot the negative of this, so that it aligns with the other methods (i.e. flipped polarity corresponds to a lower/negative value):

# as we know the expected answer in this walkthrough,
# select colors to highlight F07 and F09 (who have flipped EEG)
# (nb. assumes all dataframes have similar structure, which they do here)
pal <- rep( "gray" , dim(p1)[1] )
pal[ p1$ID == "F07" ] <- "orange"
pal[ p1$ID == "F09" ] <- "purple"

par(mfcol=c(1,3))

plot( -1 * p1$T_DIFF , col=pal, pch=20, xaxt='n',
      xlab="Individuals/channels", ylab="POL statistic" )
abline( h = 0 ) 

plot( log2(p2$SO_DUR_POS / p2$SO_DUR_NEG ) , col=pal , pch=20 , xaxt='n',
      ylab="log2( positive/negative SO duration )" , xlab="Individuals/channels" )
abline( h = 0 )

plot( p3$COUPL_ANGLE , col=pal , pch=20 , ylim=c(0,360), xaxt='n',
      ylab="SO phase angle" , xlab="Individuals/channels" ) 
abline( h = 180 )  

img

The subplots above show the means of these three statistics for C3 and C4 channel, with the colored points indicating the two people (F07 in orange and F09 in purple) who we know were manipulated to have flipped EEGs. We can clearly see that for all three metrics these two individuals are outliers with respect to all other individuals. The natural conclusion would be to flip the EEG (e.g. with Luna's FLIP command prior to making a final dataset (we'll do this later).

Limits on resolving EEG polarity

As noted above, these approaches may work less well in unusual samples, e.g. with low spindle rates, or samples without accurate sleep staging, etc. These methods also assume that polarity is constant across the entire recording. Also, in practice, only some channels may be reversed. The choice of reference electrode could influence these statistics; further, you may find individuals with ambiguous values. Also, the spindle/SO phase coupling metric may perform less well for channels that have lower rates of fast spindles, etc.


Next, we've move on to reviewing annotations, including the existing (manual) staging.