scripts/channelClasses/mock_oddb/Simple.java
/////////////////////////////////////////////////////////////////
// This script generates (somewhat) realistic ODDB data.
//
// Run with (for example)
// java -cp build:lib/derby.jar -Dserver.cache.enable=false -Djava.library.path=c frontendClasses/CLI -source mock_oddb -scriptChannel mock_oddb/Simple -reviewSeries -paradigm oddb -binH stim -binZ site -display "TiledStack()" -v
/////////////////////////////////////////////////////////////////
package mock_oddb;
import java.io.*;
import java.util.*;
import epochClasses.*;
import generalClasses.*;
import recordingClasses.Recording;
import seriesClasses.*;
import seriesClasses.seriesGeneration.Erlang;
import channelClasses.ChannelScript;
import static channelClasses.Channel.*;
/////////////////////////////////////////////////////////////////
/** This script generates (somewhat) realistic ODDB data.
* The EEG contains 280 backgrounds, and 60 targets.
*
* <p>The intended effect is:
* <ol><li>Demonstrate event generation</li>
* </ol>
*/
public class Simple extends ChannelScript
{
/** Recording instance to be operated on */
Recording rec = null;
/** Time series */
ArrayList<SeriesAnalog> list = new ArrayList<SeriesAnalog>();
/** Events. May be left empty */
ArrayList<Event> ev = new ArrayList<Event>();
////////////////////////////////////////////////////////////////////
/** Initialize instance by setting its parameters to default values.
*/
public Simple(Recording rec) {
this.rec = rec;
} // Simple
////////////////////////////////////////////////////////////////////
/** Update recording data by performing channel-oriented operations.
*/
public void update() {
// Template - used to encapsulate all sampling characteristics
float x0 = 0.0f; // in seconds: times start at x0
float xDelta = 0.004f; // in seconds: times increment by xDelta
float duration = 359.0f; // in seconds: times end at x0+duration
int nIndexes = Math.round(duration/xDelta);
SeriesAnalog template = new SeriesAnalog(new SiteSet(), // sites
x0, // x0
xDelta, // xDelta
new Units(Unit.s), // xUnits
nIndexes, // # samples
new Units(Unit.uV), // yUnits
DataMode.EEG); // DataMode
// Channels
String[] labels = {"Fz", "C3", "Cz", "C4", "Pz", "ECG"};
// Standard ERP; update event list also
SeriesAnalog erp = getEegWithErps(template);
// Generate time series
for(int site=0; site<labels.length; site++) {
// What modality?
DataMode mode = DataMode.EEG;
if(labels[site].matches("[eE][oO][gG].*")) mode=DataMode.EOG;
else if(labels[site].matches("[eE][cCkK][gG].*"))mode=DataMode.ECG;
// New series
SeriesAnalog sum = null;
if(mode.equals(DataMode.EEG)) {
// Create sum of noise and ERPs
float t0 = 0.09f;
sum = getEegWithAlpha(template, t0);
sum.add(erp);
} else if(mode.equals(DataMode.ECG)) {
sum = getEcg(template);
}
sum.setSites(new SiteSet(new Site(labels[site])));
sum.setMode(mode);
// Append sum to result
list.add(sum);
}
// Add synthetic time series to the currently empty Recording
replaceAllSeries(rec, list);
replaceAllEvents(rec, ev);
} // update
////////////////////////////////////////////////////////////////////
/** Dump summary of this class or object
* @return String representation of this object
*/
public String toString() {
String s = "<<<"+this.getClass().toString()+">>>\n";
return s;
} // toString
////////////////////////////////////////////////////////////////////
/** Generate pseudo EEG containing ERPs. Also update the event list, ev.
* The event labels must match those in SeriesBinary.buildXXX_NS5Event().
* The ERP is about +15 uV in amplitude.
*/
private SeriesAnalog getEegWithErps(SeriesAnalog template) {
float erpDuration = 1.0f;
float xDelta = template.getXDelta(); // sampling interval, in seconds
int nIndexes = Math.round(erpDuration/xDelta);
if((nIndexes&1)==0) nIndexes++;
float x0 = -(nIndexes-1)*xDelta/2; // so wavelet is centred on 0 secs
SeriesAnalog wavelet = new SeriesAnalog(new SiteSet(), // sites
x0, // x0
xDelta, // xDelta
new Units(Unit.s), // xUnits
nIndexes, // # samples
new Units(), // yUnits
DataMode.EEG); // DataMode
float lnorm = -1.0f;
SeriesAnalog erp =SeriesAnalog.getModelledErpTimeseries(wavelet,lnorm);
// Generate multiple impulses, y[], with modulated areas, plus events
String[] stim = {
"Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Tg", "Bg", "Bg", // 0
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", // 10
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Tg", "Bg", // 20
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Tg", // 30
"Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 40
"Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", // 50
"Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Tg", "Bg", // 60
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", // 70
"Bg", "Bg", "Bg", "Tg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", // 80
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Tg", // 90
"Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", // 100
"Tg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", // 110
"Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 120
"Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 130
"Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 140
"Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", // 150
"Tg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", // 160
"Bg", "Tg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg", // 170
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 180
"Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", // 190
"Tg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", // 200
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", // 210
"Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Tg", // 220
"Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Tg", "Bg", "Tg", "Bg", // 230
"Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 240
"Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Tg", "Bg", "Bg", // 250
"Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 260
"Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg", // 270
"Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 280
"Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 290
"Bg", "Tg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg", "Bg", // 300
"Bg", "Tg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", "Bg", // 310
"Bg", "Bg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Bg", // 320
"Bg", "Tg", "Bg", "Bg", "Tg", "Bg", "Bg", "Bg", "Bg", "Tg" // 330
};
int nEvents = stim.length;
float[] y = new float[template.getNIndexes()];
double meanRT = 0.32; // mean RT in seconds
Erlang ran = new Erlang(meanRT/4, 4, 0);// 'mu' or 'scale' = mean/4,k=4
// SD of distrib = sqrt(k)*'mu'
for(int i=0; i<nEvents; i++) {
float time = template.getFirstX() + 1.060f + i*1.052f;
String label = null;
float scale = 0;
double rt = 0;
if(stim[i].equalsIgnoreCase("Tg")) {
label = "Tone:1000Hz";
scale = 1.8f;
rt = ran.gen();
} else {
label = "Tone:500Hz";
scale = 1.0f;
rt = 0;
}
int offset = template.getIndex(time);
if(offset>=0 && offset<template.getNIndexes())
y[offset] = scale;
ev.add(new Event(time, 0, 0.050, label));
if(rt>0.2 && rt<1.0)
ev.add(new Event(time+rt, "Butt:L"));
}
SeriesAnalog s = new SeriesAnalog(template,y);
return s.convolveAsym(erp);
} // getEegWithErps
////////////////////////////////////////////////////////////////////
/** Generate pseudo EEG containing alpha
*/
private SeriesAnalog getEegWithAlpha(SeriesAnalog template, float t0) {
float lnorm = 2.5f;
return SeriesAnalog.getModelledEegTimeseries(template,t0,lnorm);
} // getEegWithAlpha
////////////////////////////////////////////////////////////////////
/** Generate pseudo ECG.
* The wavelet is a standard ERP, but deliberately truncated to
* make it more spike-like.
* The ECG will have R-R intervals of 0.80+var seconds, where 'var'
* has a gamma distribution, with mean equal to 0.1 seconds.
*/
private SeriesAnalog getEcg(SeriesAnalog template) {
float ecgDuration = 0.2f;
float xDelta = template.getXDelta(); // sampling interval, in seconds
int nIndexes = Math.round(ecgDuration/xDelta);
if((nIndexes&1)==0) nIndexes++;
float x0 = -(nIndexes-1)*xDelta/2; // so wavelet is centred on 0 secs
SeriesAnalog wavelet = new SeriesAnalog(new SiteSet(), // sites
x0, // x0
xDelta, // xDelta
new Units(Unit.s), // xUnits
nIndexes, // # samples
new Units(), // yUnits
DataMode.ECG); // DataMode
float lnorm = -5.0f;
SeriesAnalog erp =SeriesAnalog.getModelledErpTimeseries(wavelet,lnorm);
Erlang ran = new Erlang(0.1/5, 5, 0); // scale = mean/5
ArrayList<Float> timesList = new ArrayList<Float>();
float t = template.getFirstX()+0.3f; // time of first ECG event
float duration = template.getXDelta()*template.getNIndexes();
while(t<duration) {
timesList.add(new Float(t));
t += (float)(0.8+ran.gen());
}
float[] times = new float[timesList.size()];
for(int i=0; i<timesList.size(); i++) times[i] = timesList.get(i);
return SeriesAnalog.getImpulseTimeseries(template,times)
.mul(xDelta).convolveAsym(erp);
} // getEcg
}