package org.signalml.domain.signal.export.eeglab;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.signalml.app.document.TagDocument;
import org.signalml.app.document.signal.SignalDocument;
import org.signalml.app.model.signal.SignalExportDescriptor;
import org.signalml.app.view.signal.SampleSourceUtils;
import org.signalml.domain.signal.SignalWriterMonitor;
import org.signalml.domain.signal.export.ISignalWriter;
import org.signalml.domain.signal.samplesource.MultichannelSampleSource;
import org.signalml.plugin.export.signal.Tag;
import org.signalml.util.matfiles.CompressedMatlabFileWriter;
import org.signalml.util.matfiles.MatlabFileWriter;
import org.signalml.util.matfiles.array.AbstractArray;
import org.signalml.util.matfiles.array.CharacterArray;
import org.signalml.util.matfiles.array.DoubleArray;
import org.signalml.util.matfiles.array.IntegerArray;
import org.signalml.util.matfiles.array.lazy.LazyExportDoubleArray;
import org.signalml.util.matfiles.structure.Structure;
/**
* Exports signal to EEGLab format.
*
* @author Tomasz Sawicki
*/
public class EEGLabSignalWriter implements ISignalWriter {
private SortedSet<Tag> allTags;
private SignalDocument signalDocument;
public void setSignalDocument(SignalDocument signalDocument) {
this.signalDocument = signalDocument;
}
/**
* Extracts all the tags from signal document
*
* @param signalDocument
* the signal document which has tags
* @return SortedSet<Tag> all tags from this signal document
* @author Maciej Pawlisz
*/
private SortedSet<Tag> extractTags(SignalDocument signalDocument) {
List<TagDocument> tagDocuments = signalDocument.getTagDocuments();
SortedSet<Tag> tags = new TreeSet<Tag>();
for (int d = 0; d < tagDocuments.size(); d++)
tags.addAll(tagDocuments.get(d).getTagSet().getTags());
return tags;
}
/**
* Writes the signal to a file in EEGLab format.
*
* @param outputPath
* output file path
* @throws IOException
* when the file cannot be writen
*/
public void writeSignal(File output, MultichannelSampleSource sampleSource, SignalExportDescriptor descriptor, SignalWriterMonitor monitor) throws IOException {
int channelCount = sampleSource.getChannelCount();
int sampleCount = SampleSourceUtils.getMinSampleCount(sampleSource);
String[] channelNames = new String[channelCount];
int referenceChannel = 0;
for (int i = 0; i < channelCount; i++) {
channelNames[i] = sampleSource.getLabel(i);
if (sampleSource.getLabel(i).equals("Fz")) {
referenceChannel = i;
}
}
double samplingRate = sampleSource.getSamplingFrequency();
Structure eegStruct = new Structure("EEG");
String filename = output.getName();
eegStruct.setField("setname", new CharacterArray("setname", filename.substring(0, filename.lastIndexOf("."))));
eegStruct.setField("filename", new CharacterArray("filename", filename));
eegStruct.setField("trials", new DoubleArray("trials", new double[] { 1.0 }));
eegStruct.setField("pnts", new DoubleArray("pnts", new double[] { (double) sampleCount }));
eegStruct.setField("nbchan", new DoubleArray("nbchan", new double[] { (double) channelCount }));
eegStruct.setField("srate", new DoubleArray("srate", new double[] { samplingRate }));
eegStruct.setField("xmin", new DoubleArray("xmin", new double[] { 0.0 }));
eegStruct.setField("xmax", new DoubleArray("xmax", new double[] { sampleCount / samplingRate }));
eegStruct.setField("ref", new IntegerArray("ref", new Integer[] { referenceChannel }));
eegStruct.setField("saved", new CharacterArray("saved", "no"));
eegStruct.setField("icawinv", new DoubleArray("icawinv", new Double[][] { {} }));
eegStruct.setField("icaweights", new DoubleArray("icaweights", new Double[][] { {} }));
eegStruct.setField("icasphere", new DoubleArray("icasphere", new Double[][] { {} }));
eegStruct.setField("icaact", new DoubleArray("icaact", new Double[][] { {} }));
List<String> keys = new ArrayList<String>();
List<AbstractArray> arrays = new ArrayList<AbstractArray>();
keys.add("labels");
for (int i = 0; i < channelCount; i++) {
arrays.add(new CharacterArray("labels", channelNames[i]));
}
Structure chanlocs = new Structure("chanlocs");
chanlocs.setFieldsForStructureArray(keys, arrays);
eegStruct.setField("chanlocs", chanlocs);
if (signalDocument != null && descriptor.isExportTags())
eegStruct.setField("event", getEventStruct(samplingRate));
LazySampleProvider lazySampleProvider = new LazySampleProvider(sampleSource);
lazySampleProvider.setSignalWriterMonitor(monitor);
eegStruct.setField("data", new LazyExportDoubleArray("data", lazySampleProvider));
MatlabFileWriter writer = new CompressedMatlabFileWriter(output);
writer.addElement(eegStruct);
writer.write();
if (monitor != null) {
monitor.setProcessedSampleCount(sampleCount);
}
}
/**
* Returns event EEGLab event structure
*
* @return MLStructure event structure
* @author Maciej Pawlisz
*/
private Structure getEventStruct(double samplingRate) {
allTags = extractTags(signalDocument);
List<String> keys = new ArrayList<String>();
keys.add("type");
keys.add("latency");
keys.add("duration");
keys.add("tag_type");
keys.add("channel");
List<AbstractArray> arrays = new ArrayList<AbstractArray>();
for (Iterator<Tag> it = allTags.iterator(); it.hasNext();) {
Tag tag = it.next();
arrays.add(new CharacterArray("type", tag.getStyle().getName()));
arrays.add(new DoubleArray("latency", new double[] { tag.getPosition() * samplingRate }));
arrays.add(new DoubleArray("duration", new double[] { tag.getLength() * samplingRate }));
arrays.add(new CharacterArray("tag_type", tag.getType().getName()));
arrays.add(new IntegerArray("channel", new Integer[] { tag.getChannel() }));
}
Structure eventStruct = new Structure("event");
eventStruct.setFieldsForStructureArray(keys, arrays);
return eventStruct;
}
}