scripts/channelClasses/standard/A1A2Ref.java
/////////////////////////////////////////////////////////////////
// Processes data by rereferencing EEG channels to (A1+A2)/2
//
// This code is compiled at runtime, but compilation can be tested by:
// javac -cp build scripts/channelClasses/standard/A1A2Ref.java
// rm scripts/channelClasses/standard/A1A2Ref.class
/////////////////////////////////////////////////////////////////
package standard;
import java.io.*;
import java.util.*;
import generalClasses.*;
import recordingClasses.Recording;
import seriesClasses.*;
import channelClasses.ChannelScript;
import static channelClasses.Channel.*;
/////////////////////////////////////////////////////////////////
/** Processes data by rereferencing EEG channels to (A1+A2)/2. <b>It
* (probably) should only be applied to common-ref data, and
* probably should only be called if A1 and A2 are known not be noisy.</b>
*
* <p>NB 1. This algorithm simply subtracts (A1|xx + A2|xx)/2 from all
* EEG waveforms. <b>As such, it makes clearest sense when all EEG
* channels are monopolar, or have 'xx' as their common reference.</b>
* <p>NB 2. Subtracting (A1+A2)/2 only makes sense if neither
* A1 nor A2 are affected by artifact; or if artifact is common to
* all EEG channels. It is common to use A1A2Ref to get rid of
* noise due to the virtual ground of CNT recordings, and then to
* use Standard to eliminate channels with extra noise, e.g.<pre>
* -scriptChannel A1A2Ref:Standard
* </pre>
*
* <p>The effect of referencing can be seen be comparing the result
* of <pre>
* java -cp build:lib/derby.jar frontendClasses/CLI -fn data/81237443-1.EC.NS5 -scriptChannel A1A2Ref:Standard -paradigm ec -scriptEpoch OneLong -chanSelection "Mode='EEG'" -reviewSeries
* </pre>
* with and without 'A1A2Ref:' in the command line.
*/
public class A1A2Ref extends ChannelScript
{
/** Recording instance to be operated on */
Recording rec = null;
/** Log of warnings generated during update */
ArrayList<String> warnings = new ArrayList<String>();
////////////////////////////////////////////////////////////////////
/** Initialize instance by setting its parameters to default values.
*/
public A1A2Ref(Recording rec) {
this.rec = rec;
} // A1A2Ref
////////////////////////////////////////////////////////////////////
/** Update recording data by performing channel-oriented operations.
* <p>Available modes are EEG, EOG, REF, EMG, EDA, RES, ECG, EVE.
*/
public void update() {
// Partition results into ref, EEG and non-EEG channels
ArrayList<SeriesAnalog> refs = selectSite(rec, "A[12]");
ArrayList<SeriesAnalog> result = selectMode(rec, DataMode.EEG);
ArrayList<SeriesAnalog> rest = discardMode(rec, DataMode.EEG);
// Check that the reference channels are unambiguous
if(refs.size()==0 || refs.size()==1) {
warnings.add("Script failure in A1A2Ref: can't find 'A1' and 'A2'");
return;
}
if(refs.size()>2) {
warnings.add("Script failure in A1A2Ref: found multiple A1 or A2");
return;
}
// Compute ref = (A1+A2)/2
SeriesAnalog ref = refs.get(0).clone();// This is new reference channel
ref.add(refs.get(1));
int nAveraged = 2;
ref.div(nAveraged);
ref.setSites(new SiteSet(new Site("A1A2")));
// Ideally, check that all EEG channels have a common reference,
// and, if not, create a warning or error.
// Rereference the EEG, and merge with non-EEG channels
for(SeriesAnalog c: result)
c.sub(ref);
result = listsUnion(result, rest);
// Update Recording object
replaceAllSeries(rec, result);
} // update
////////////////////////////////////////////////////////////////////
/** Dump summary of this class or object
* @return String representation of this object
*/
public String toString() {
String s = "<<<"+this.getClass().toString()+">>>\n";
s += "Re-references EEG channels by subtracting (A1+A2)/2\n";
for(String w: warnings)
s += w+"\n";
return s;
} // toString
}