How to compute and display scalp potentials from EEG recordings

EEG researchers commonly create spatial maps of the electrical activity acros the scalp. Data are interpolated or triangulated from a discrete number of electrode placements distributed across the scalp (generally greater than 32 sites) often in fixed/standardized positions (see, e.g.,  To do this, electrode coordinates, either as {x, y, z} triplets or in spherical coordinates are needed and can be obtained from the manufacturer of electrode caps (e.g.,  

Theoretical analysis typically involves modeling the head as a perfect sphere.  The mapping of the electrode coordinates to the surface of a sphere can be accomplished with the following function:

Function scaleToSpherical(inWave)
    Wave inWave
    // offset the coordinates to the  origin:
    MatrixOP/o/free wave0c=subtractMean(inWave,1)
    // compute the distance of electrodes from the origin:
    MatrixOP/O/free rawRad=sqrt(magsqr(col(wave0c,0))+magsqr(col(wave0c,1))+magsqr(col(wave0c,2)))
    // rescale the distance to a radius of 1:
    MatrixOP/O centeredNormalized=scalerows(wave0c,rec(rawRad))
Figure 1: Initial electrode positions relative to the surface of a sphere.

Figure 1: Initial electrode positions relative to the surface of a sphere.

Figure 2: Normalized electrode coordinates on the surface of a sphere.

Figure 2: Normalized electrode coordinates on the surface of a sphere.

Using the normalized set of coordinates we can triangulate the data on the surface of a sphere using the SphericalTriangulate operation. 

SphericalTriangulate centeredNormalized // this creates M_TriangulationData

Following the triangulation we can use the wave M_TriangulationData combined with the EEG data to interpolate the potentials at any point on the sphere.  In order to display the resulting interpolation in Gizmo we start by creating a parametric surface representing the sphere. 

Function makeParametricSphere(pointsx,pointsy)
    Variable pointsx,pointsy
    Variable i,j,rad
    Make/O/N=(pointsx,pointsy,3) parametricW
    Variable anglePhi,angleTheta
    Variable dPhi,dTheta
    Variable xx,yy,zz
    Variable sig

To complete the interpolation we need to construct one more wave: dataPointsWave.  This wave has 4-columns consisting of the electrode coordinates in the first three columns and the potentials measured by each electrode at some fixed time t0 in the fourth column:

    Variable nRows=DimSize(centeredNormalized,0)
    Make/O/D/N=(nRows,4) dataPointsWave

The interpolation is computed by:

    SphericalInterpolate M_TriangulationData,dataPointsWave,sphereData

The resulting interpolation is stored in the wave W_SphericalInterpolation where each row contains the scalar potential interpolated for the corresponding XYZ location in the wave sphereData.  To display these values on the parametric surface we need to construct a color wave

Function createParametricColorWave(pWave,interpWave,reverseCTAB)
    Wave pWave,interpWave
    Variable reverseCTAB            // set to 1 to reverse; 0 otherwise
    // the color wave must match the parametric surface:
    Variable rows=dimsize(pwave,0)
    Variable cols=dimSize(pWave,1)
    // Create the parametric color wave:
    Make/O/N=(rows,cols,4) pWaveColor=1     
    // find the range of values for scaling:
    Variable mmax=WaveMax(interpWave)
    Variable mmin=WaveMin(interpWave)
    // optionally replace the colortable here:
    ColorTab2Wave rainbow256
    Wave M_Colors
    // not all colortables have the same number of colors:
    Variable nTableCols=DimSize(M_Colors,0)-1

        MatrixOP/o/free aa=col(M_Colors,0)
        WaveTransform/o flip aa
        MatrixOP/O M_Colors=setCol(M_Colors,0,aa)
        MatrixOP/o/free aa=col(M_Colors,1)
        WaveTransform/o flip aa
        MatrixOP/O M_Colors=setCol(M_Colors,1,aa)
        MatrixOP/o/free aa=col(M_Colors,2)
        WaveTransform/o flip aa
        MatrixOP/O M_Colors=setCol(M_Colors,2,aa)
    MatrixOP/O M_Colors=fp32(M_Colors/65535)
    Variable nor=nTableCols/(mmax-mmin)
    Variable i, np=rows*cols,index,rr,cc

An example of this approach is illustrated in a cross-lingustic speech discrimination study at the following webpage:

Valerie L. Shafer, Ph.D.
Professor and Deputy Executive Officer
Ph.D. Program in Speech-Language-Hearing Sciences
The Graduate Center, CUNY
365 Fifth Avenue, NY, NY 10016

Macintosh 64-bit XOPs and Igor Pro 8

There is an issue that will affect Macintosh 64-bit XOPs running with Igor Pro 8. We don't know when we will start beta testing Igor8, but it will be no earlier than the fall of 2017.

The short story is that, because of a change in Igor8, existing Macintosh 64-bit XOPs need to be modified and recompiled with XOP Toolkit 7.01 or later to run with the 64-bit version of Igor Pro 8 on Macintosh. Macintosh 32-bit XOPs as well as Windows 32-bit and 64-bit XOPs will run with Igor8 without modification.

The 64-bit Macintosh version of Igor7 uses Mac OS handles both internally and to exchange data with XOPs. Mac OS handles are limited to roughly 2^31 bytes, even in 64-bit applications. To overcome this limit, the Macintosh 64-bit version of Igor8 will use WaveMetrics handles - that is, handles created and manipulated using WaveMetrics code, as all Windows versions have always done.

XOP Toolkit 7.01 provides the necessary support to allow Macintosh 64-bit XOPs to use WaveMetrics handles. It adds WaveMetrics memory management XOPSupport routines that allow an XOP to use compatible handles no matter what version of Igor it is running with.

Although this change is critical only for Macintosh 64-bit XOPs, we recommend that all actively-developed XOPs be changed, when it is convenient, to use the new WaveMetrics memory management XOPSupport routines so that the source code will be compatible with any version of Igor on any platform. The source code changes required are minimal and amount mostly to changing NewHandle to WMNewHandle, DisposeHandle to WMDisposeHandle, and so on.

When you are ready to update your XOP, here is what you need to do:

  1. Download the latest XOP Toolkit. If you have an XOP Toolkit 7 license, use the download instructions that you previously received from WaveMetrics. If you have an XOP Toolkit 6 license, contact WaveMetrics sales for a free upgrade to XOP Toolkit 7.
  2. If you have not yet updated your XOP Toolkit 6 XOP for XOP Toolkit 7, follow the instructions in Appendix A of the XOP Toolkit 7 manual.
  3. See Appendix C of the XOP Toolkit 7 manual for an overview of changes since the release of XOP Toolkit 7.00.
  4. Follow the link in Appendix C to the section "WM Memory XOPSupport Routines" in Chapter 12. This explains the issue in greater detail.
  5. Follow the instructions in the section "Updating Old Code to Use WM Memory XOPSupport Routines" in Chapter 12.

The XOP Toolkit 7 manual is included in the XOP Toolkit 7. It is also available from

For an overview of the XOP Toolkit, see

Get to Know a Feature: Color Table Wave Creation

Get to Know a Feature: Color Table Wave Creation

In "Get to Know a Feature: Color Table Wave Basics", we showed how Igor 7's color table waves are more flexible than Igor 6's color index waves because multiple uses of the same color table wave can cover differing Z value ranges. This post discusses several ways that you can create your own color table waves such as including importing RGB values from a CSV file and recreating a color table from a screen capture,